VIJOS P1037搭建双塔[DP]

描述

2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难。为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔。

Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建。但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少。所以他来请你帮忙。

给定水晶的数量N(1≤N≤100)和每块水晶的高度Hi(N块水晶高度的总和不超过2000),你的任务是判断Mr. F能否用这些水晶搭建成一座双塔(两座塔有同样的高度),如果能,则输出所能搭建的双塔的最大高度,否则输出“Impossible”。

格式

输入格式

输入的第一行为一个数N,表示水晶的数量。第二行为N个数,第i个数表示第i个水晶的高度。

输出格式

输出仅包含一行,如果能搭成一座双塔,则输出双塔的最大高度,否则输出一个字符串“Impossible”。

------------------------------------------------

很像多重背包可行性问题

f[i][j]表示前i块水晶搭建的双塔高度相差j时高塔的高度

不可行用-1表示

转移考虑4种情况即可(不用第i块也算)

初始化f[0][0]=0 其他-1

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=105,H=2005;
int n,h[N],sum=0,ans=0;
int f[N][H];
void dp(){
    memset(f,-1,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=sum;j++){
            //high=f[i][j],low=f[i][j]-j;
            if(f[i-1][j]!=-1) f[i][j]=f[i-1][j];
            if(j-h[i]>=0&& f[i-1][j-h[i]]!=-1) f[i][j]=max(f[i][j],f[i-1][j-h[i]]+h[i]);
            if(j-h[i]<0&& f[i-1][h[i]-j]!=-1) f[i][j]=max(f[i][j],f[i-1][h[i]-j]+j);
            if(h[i]+j<=sum&& f[i-1][j+h[i]]!=-1) f[i][j]=max(f[i][j],f[i-1][j+h[i]]);
            //printf("f %d %d %d\n",i,j,f[i][j]);
        }
}
int main(int argc, const char * argv[]) {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&h[i]),sum+=h[i];
    sum/=2;
    dp();
    if(f[n][0]>0) cout<<f[n][0];
    else cout<<"Impossible";
    return 0;
}
//http://blog.csdn.net/dongdongzhang_/article/details/9672633 滚动数组做法
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int v = 2000 + 5;
const int MaxN = 100 + 5;
int N, sum, num[MaxN], dp[2][v];
int main() {
    int i, j, k;
    cin >> N;
    for(i = 0; i < N; ++i) {
        cin >> num[i];
        sum += num[i];
    }
    memset(dp, -1, sizeof(dp));
    dp[0][0] = 0;
    int a;
    for(i = 0; i < N; ++i) {
        a = i % 2;
        memset(dp[a], -1, sizeof(dp[a]));
        for(j = 0; j <= sum; ++j) {
            //1.不放第i块水晶;
            if(dp[a ^ 1][j] > -1)
                dp[a][j] = dp[a ^ 1][j];
            //2.放进去后,高塔变矮塔(第i块放在矮塔上了);
            if(num[i] > j &&  dp[a ^ 1][num[i] - j] > -1)
                dp[a][j] = max(dp[a][j], dp[a ^ 1][num[i] - j] + j);
            //3.放进去后,高塔仍高(第i块放在矮塔上);
            if(j + num[i] <= sum && dp[a ^ 1][j + num[i]] > -1)
                dp[a][j] = max(dp[a][j], dp[a ^ 1][j + num[i]]);
            //4.放进去后,高塔更高(第i块放在高塔上).
            if(j >= num[i] && dp[a ^ 1][j - num[i]] > -1)
                dp[a][j] = max(dp[a][j], dp[a ^ 1][j - num[i]] + num[i]);
        }
    }
    if(dp[a][0] > 0)
        cout << dp[a][0] << endl;
    else
        cout << "Impossible" << endl;
}
时间: 2024-10-27 08:53:10

VIJOS P1037搭建双塔[DP]的相关文章

vijos P1037搭建双塔

P1037搭建双塔 Accepted 标签:动态规划 背包 描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔. Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建.但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少.所以他来请你

shu_1299 vijos 1037(搭建双塔)

http://202.121.199.212/JudgeOnline/problem.php?cid=1078&pid=7 分析: 经典DP题 dp[ i ][ j ]:前i个水晶搭建的高度差为 j 的双塔中较高塔的高度: dp[ i ][ j ] = d[ i-1 ][ j ]  ,                       不放第i个水晶: dp[ i ][ j ] = f[ i-1 ][ h[i]-j ] + j,               第i个水晶放在较矮的塔上,原来较矮的塔变成较

vijos 1037 搭建双塔 【DP】

% 这题是小猫给我讲的 % 题目: Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建.但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少.所以他来请你帮忙. 给定水晶的数量N(1≤N≤100)和每块水晶的高度Hi(N块水晶高度的总和不超过2000),你的任务是判断Mr. F能否用这些水晶搭建成一座双塔(两座塔有同样的高度),如果能,则输出所能搭建

vijos 1243 生产产品 DP + 单调队列优化

LINK 题意:有1个产品,m个步骤编号为1~m.步骤要在n个机器人的手中生产完成.其中,第i个步骤在第j个机器人手中的生产时间给定为$T[i][j]$,切换机器人消耗cost.步骤必须按顺序,同一个机器人不能连续完成超过l个步骤.求完成所有步骤的最短时间是多少.其中$m<=10^5$,$n<=5$,$l<=5*10^4$ 思路:这题用DP考虑易得一个转移方程$dp[i][j]=\min^{i-1}_{v=i-L}{(dp[v][x] + sum[i][j] - sum[v][j]) +

ZOJ 2059 The Twin Towers(双塔DP)

The Twin Towers Time Limit: 2 Seconds      Memory Limit: 65536 KB Twin towers we see you standing tall, though a building's lost our faith will never fall. Twin towers the world hears your call, though you're gone it only strengthens our resolve. We

Laoj P1299 搭建双塔

试题描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念"9?11"事件,Mr. F决定自己用水晶来搭建一座双塔. Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建.但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少.所以他来请你帮忙. 给定水晶的数量N(1≤N≤100)和每

tyvj1114 搭建双塔

描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔.    Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建.但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少.所以他来请你帮忙.    给定水晶的数量N(1≤N≤100)和每块

vijosP1037搭建双塔

链接:https://vijos.org/p/1037 [思路] DP. [代码] 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 const int maxn = 100+10; 6 7 int a[maxn]; 8 int d[maxn][2010]; 9 int n,sum; 10 11 int main() { 12 ios::sync_with_stdio(false); 13 cin

Vijos p1518河流 树形DP

https://vijos.org/p/1518 这题代码我基本是抄的,实在太难想了.但是也学到了一些东西. 比如:多叉树转二叉树存,这个细细一想,确实使得在dfs的时候,实现起来方便很多. 说一说具体 dfs的思路,思路和网上那个一模一样的,我刚学树形dp,可能上网看看总结下套路比较好. 设dfs(cur, hasPoint, k, dis)表示,现在处理到cur这个节点,离cur最近的那个仓库节点是hasPoint, 剩下k次设置仓库的机会,还有就是cur的爸爸距离hasPoint的距离.