描述
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
来源
某校NOIP模拟题
dp[i][j]表示对于前i个物体,构成差值为j是的塔高。我们默认记录的是高塔
有四种情况。对于当前插值为j,物体为i。
如果差值j大于物体高度,我们必须放到高塔上,才能保证达到差值j。所以dp[i-1][j-a[i]]+a[i];
如果差值j小于物体高度,我们要放到小塔上,并使得小塔变成大塔,使的高度差为j。 那么就是我们要找一个 dp[i - 1][a[i] - j] + j
第三种情况就是直接放到小塔上,似的插值为j。dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i]]);
最后就是不放 dp[i][j] = max(dp[i][j], dp[i - 1][j]);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include <fstream>
#include<vector>
#include<math.h>
using namespace std;
int dp[1000][1000];
int a[1100];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
}
memset(dp, -0x3f, sizeof dp);
dp[0][0] = 0;//dp[i][j]表示前i个木块组成的双子塔的差值为j时的长度
for (int i = 1; i <= n; ++i)//对于当前木块
{
for (int j = 0; j <= 2000; ++j) //形成j的差值
{
if (j >= a[i])//如果我们想要形成的插值大于当前木块长度,那肯定是往高的那个塔放
{
dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i]] + a[i]); //放去高的上头.
}
if (a[i] >= j) //如果小于,我们放到小的上头并使小的变得高的,插值为j
{ //我们本来A小B大,AB差值为a【i】-j.我们想要插值为j
dp[i][j] = max(dp[i][j], dp[i - 1][a[i] - j] + j);
}
dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i]]); //放在小的那里
dp[i][j] = max(dp[i][j], dp[i - 1][j]); //不用
}
}
if (dp[n][0] <= 0) {
cout << "Impossible" << endl;
}
else
cout << dp[n][0] << endl;
}