vijosp1037-类背包问题&好题-搭建双塔

来源:互联网 发布:公司网络改造 编辑:程序博客网 时间:2024/06/07 13:43

https://vijos.org/p/1037
问你用以下的数字构建两个 相同高度的双塔,尽可能的高。
开始的思路是 背包计数。
如果 dp[m] 和dp[m/2] 和m%2==0 都满足,那么我们就可以输出m/2
(m和 m/2 这些数字都能拼出来。。)
但是即使这样,其实也不一定是可以的,因为很可能 m/2构成的两次使用了重叠的项,而我们并没有阻止这一种情况

// 这时错误的代码。过了不到一半的数据qwq#include <bits/stdc++.h>using namespace std;const int maxn=3000;int a[maxn];int dp[maxn];int m;int main(){    scanf("%d",&m);     int sum=0;     for(int i=0;i<m;i++){         scanf("%d",&a[i]);         sum+=a[i];     }     memset(dp,0,sizeof(dp));     dp[0]=1;     for(int i=0;i<m;i++){        for(int j=sum;j>=a[i];j--)            dp[j]+=dp[j-a[i]];     }     int x=sum;     while(1){        if(dp[x]&&x%2==0&&dp[x/2]>=2){        printf("%d\n",x/2);        break;        }        else            x--;     }    return 0;}

正解是 类似背包的dp
dp[i][j] 表示使用了1-i个数字,两个塔差值为j时候 矮塔的个数。

#include <bits/stdc++.h>using namespace std;const int inf=0x3f3f3f3f;const int maxn=3000;int a[maxn];int dp[2][maxn];int m;int main(){    scanf("%d",&m);     int sum=0;     for(int i=1;i<=m;i++){         scanf("%d",&a[i]);         sum+=a[i];     }    for(int i=0;i<2;i++){        for(int j=1;j<maxn;j++)            dp[i][j]=-inf;    }     for(int i=1;i<=m;i++){        for(int j=0;j<=sum;j++){            dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j]);//不使用 当前第i个数字            if(j>=a[i])            dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j-a[i]]);            // 将这个数字放在高塔上。(这点注意思考)            if(j+a[i]<=sum)            dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j+a[i]]+a[i]);// 放在矮塔上。大小并未改变。            if(j<a[i])            dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][a[i]-j]+a[i]-j);//放在矮塔上,埃塔变成了高塔。(这个数字大于差值。改变了            )        }     }     bool flag=false;     if(dp[(m)%2][0]){        printf("%d\n",dp[(m)%2][0]);         flag=true;         }     if(!flag)        puts("Impossible");    return 0;}
原创粉丝点击