【洛谷 P1651】 塔

题目链接
题意:\(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\n", !dp[0][n%2] ? -1 : dp[0][n%2]);
    Close;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Qihoo360/p/9660248.html
今日推荐