vijos p1037——搭建双塔

描述

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”。

样例1

样例输入1

5
1 3 4 5 2

样例输出1

7
 
 
dp[i][j]表示前i点高度差为j的方案数
由于j代表高度差,所以有4种情况:
放低塔但仍其为低塔,高度差减小、
放低塔但成为高塔、
放高塔,仍为高塔、
不放。
dp初值:先全部赋为负数,然后dp[1][0]赋为0

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1005;
 4 const int maxh=2005;
 5 int dp[maxn][maxh];//前i点高度差为j
 6 int h[maxn];
 7 int n,sum[maxn];
 8 int main()
 9 {
10     memset(dp,-0x7f,sizeof(dp));
11     scanf("%d",&n);
12     for(int i=1;i<=n;i++)
13     scanf("%d",&h[i]);
14     sort(h+1,h+n+1);
15     for(int i=1;i<=n;i++)
16     sum[i]=sum[i-1]+h[i];
17     dp[1][0]=0;dp[1][h[1]]=0;
18     for(int i=2;i<=n;i++)
19     for(int j=0;j<=sum[i];j++)
20     {
21         int h1=j;//不放 
22         dp[i][j]=max(dp[i][j],dp[i-1][h1]);
23         
24         int h2=j-h[i];//放高塔
25         if(h2>=0)
26         dp[i][j]=max(dp[i][j],dp[i-1][h2]);
27         
28         int h3=h[i]-j;//放低塔使其成为高塔
29         if(h3>=0)
30         dp[i][j]=max(dp[i][j],dp[i-1][h3]+h3);
31         
32         int h4=j+h[i];//放低塔仍为低塔
33         dp[i][j]=max(dp[i][j],dp[i-1][h4]+h[i]); 
34     }
35     if(dp[n][0]<=0)printf("Impossible");
36     else printf("%d",dp[n][0]);
37     return 0;
38 } 


 
原文地址:https://www.cnblogs.com/937337156Zhang/p/6044273.html