题目链接
题意:(n)个木块放到两个塔里,每个木块可放可不放,使得两塔高度相同且高度最大,求最大高度。
这个差值(DP)的思维难度还是很大的,没想出来,我就打了一个(dfs)骗了好像(20)还是(30)分吧(看来搜索也写挂)。
正解是(DP),(f[i][j])表示前(i)块木块使得两个塔的高度差为(k)时高度最大的那个是什么(神奇的状态)
那么无非就(4)种情况:
1、第(i)块不放:(f[i][j]=f[i-1][j])
2、第(i)块放到矮的上面,矮的仍然矮:(f[i][j]=f[i-1][j+a[i]])
3、第(i)块放到高的上面,高的当然高:(f[i][j]=f[i-1][j-a[i]]+a[i])
4、第(i)块放到矮的上面,矮的变高的:(f[i][j]=f[i-1][a[i]-j]+j)
可以发现,(f[i])的取值仅与(f[i-1])有关,于是第一维是可以滚掉的。
#include <cstdio>
#include <cstring>
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
const int MAXN = 55;
const int MAX = 500010;
int dp[MAX][2];
inline int max(int a, int b){
return a > b ? a : b;
}
int n, s[MAXN], sum;
int main(){
Open("tower");
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &s[i]), sum += s[i];
memset(dp, 128, sizeof dp);
dp[0][0] = dp[0][1] = 0;
for(int i = 1; i <= n; ++i)
for(int j = sum; ~j; --j){
dp[j][i%2] = dp[j][!(i%2)];
if(j + s[i] <= sum) dp[j][i%2] = max(dp[j][i%2], dp[j + s[i]][!(i%2)]);
if(j - s[i] >= 0) dp[j][i%2] = max(dp[j][i%2], dp[j - s[i]][!(i%2)] + s[i]);
if(j < s[i]) dp[j][i%2] = max(dp[j][i%2], dp[s[i] - j][!(i%2)] + j);
}
printf("%d
", !dp[0][n%2] ? -1 : dp[0][n%2]);
Close;
return 0;
}