最近几天在研究usaco,那是一个很有趣的地方,做起题来像通关游戏,所以zoj倒做得少了。不有趣的地方是一旦一道题解不出,就像碰到一位大Boss,死打也不扣血,非得你跑到城外去拼命练级方可过关。于是回过头来写写以前没做出的几道简单dp题,这就是其一。
题目的大意如下:有一列N个水晶,把他们搭成双子塔,要求塔高一样,求塔的最大高度。当初做的时候不小心看错了条件,以为每块水晶最大高度是2000,接着开了个200000的数组,自己机子都过不了。今天看了busycai的程序,才明白搞错了。总高度是2000,所以O(n) = N×2000.时间还算不错。
起初想用b[i]来表示塔高为i的某种状态(塔高之差?或是别的什么),结果想了半天不得其解。其实把设定倒过来,当bi表示塔高之差为i的时候,对总高度dp,这样就简单了。
对0<= i <= 2000,当在左或右边放入a[k]之后,差有两种可能,i + a[k], i - a[k]。然后更新,即可。
#include <cstdio>
#include <string>
int abs ( int i )
{
return i > 0 ? i : -i ;
}
int N, a[101], b[2][2001], p;
int main ()
{
//freopen ( "in.txt", "r", stdin );
while ( scanf ( "%d", &N ) && N >= 0 )
{
int i, end, j, k;
for ( i = 0; i < N; i ++ )
{
scanf ( "%d", &a[i] );
}
memset ( b, -1, sizeof ( b ) );
b[1][0] = 0, p = 0, end = 0;
for ( i = 0; i < N; i ++, p = 1 - p )
{
memcpy ( b[p], b[1 - p], sizeof ( b[p] ) );
end += a[i];
for ( j = 0; j <= end; j ++ )
{
k = abs ( j + a[i] );
if ( k <= end && b[1 - p][j] >= 0 && b[p][k] < b[1 - p][j] + a[i] )
{
b[p][j + a[i]] = b[1 - p][j] + a[i];
}
k = abs ( j - a[i] );
if ( k <= end && b[1 - p][j] >= 0 && b[p][k] < b[1 - p][j] + a[i] )
{
b[p][k] = b[1 - p][j] + a[i];
}
}
}
if ( b[1 - p][0] )
{
printf ( "%d\n", b[1 - p][0] / 2 );
}
else
{
printf ( "Sorry\n" );
}
}
return 0;
}
2238803 | 2007-02-18 16:04:42 | Accepted | 2059 | C++ | 00:00.30 | 2988K | Crux.D |
评论