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

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

// 这时错误的代码。过了不到一半的数据qwq
#include 
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;iscanf("%d",&a[i]);
         sum+=a[i];
     }
     memset(dp,0,sizeof(dp));
     dp[0]=1;
     for(int i=0;ifor(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 
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;jfor(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%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;
}

你可能感兴趣的:(动态规划,背包)