目录
一.题目:
题目描述:
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"。
样例输入:
5
1 3 4 5 2
样例输出:
7
二.题解:
一.思路:
这道题是一道经典的DP,主要用的思路是填表法,也就是顺推的思路。我们首先定义dp数组,把这个数组定义成一个二维数组,即dp[i][j],表示放了第i个水晶后,两个塔的高度相差j,其中最高的那一个塔。也就是说,i表示水晶块数,j表示两塔高度之差,dp[i][j]存其中最高的那一个塔的高度。那么,每此放水晶都有四种情况:
1.把这块水晶放在高的那一个塔上:
那么高的那一个塔就更高,j是现在放上去之后两塔的高度之差,那么原来两塔的高度之差就应该是:j - h[i],于是状态转移方程就是:dp[i][j] = max {dp[i][j], dp[i - 1][j - h[i]] + h[i]}。加h[i],是因为最高的塔变高了。
如图:
2.把这块水晶放在矮的那一个塔上,且放上去之后,矮的那一个塔仍然矮:
由此就可以推出,两个塔原来的高度差就是:,于是状态转移方程式就是:。
如图:
3.把这块水晶放在矮的那一个塔上,且放上去之后,矮的那一个塔变得比原本高的塔还高了:
同理,两个塔的原高度差是:,状态转移方程就变成了:,加j是因为最高的那个塔变成了原本矮的那个塔,而矮的那个塔又是原最高塔加上现在的两塔高度之差。
如图:
4.最后就剩一种情况,自然就是不放这块水晶,状态转移方程:;
这道题就完了,最后只需输出用了n块水晶之后,两塔高度差为0时,其中一塔高度。
二.代码实践
既然思路都知道了,那么代码实践就十分简单了。只需读入之后就进行一个二重循环的DP,最后输出就行了。只不过要注意,dp数组是需要初始化的,全部附为极小值,十分玄学,大家可以讨论一下为什么。
三.样例代码
#include <cstdio>
#include <iostream>
#include <cstring>
#define M 105
#define max(a, b) a > b ? a : b
const int MIN = -0x3f3f3f3f;//附极小值
using namespace std;
int n, h[M], dp[M][2005], sum;
int main (){
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
scanf("%d", &h[i]);
sum += h[i];
}
memset(dp, MIN, sizeof(dp));//玄学初始化
dp[0][0] = 0;//注意
for(int i = 1; i <= n; i ++){
for(int j = sum; j >= 0; j --){
if(j >= h[i])//情况一
dp[i][j] = max (dp[i][j], dp[i - 1][j - h[i]] + h[i]);
dp[i][j] = max (dp[i][j], dp[i - 1][j + h[i]]);//情况二
if(j <= h[i])//情况三
dp[i][j] = max (dp[i][j], dp[i - 1][h[i] - j] + j);
dp[i][j] = max (dp[i][j], dp[i - 1][j]);//情况四
}
}
if(!dp[n][0])//输出要注意判断无法组成双塔的情况
printf("Impossible\n");
else
printf("%d\n", dp[n][0]);
return 0;
}
三.总结
这道动态规划十分的经典,主要是对于四种情况的考虑。其实我是在草稿纸上写写画画,搞出了这些情况,没想到就对了。所以,做题的时候光有聪明的头脑是远远不够的,草稿纸十分重要,特别是对于DP题,需要推出状态转移方程式。加油吧,DP总是会越做越有经验的!谢谢!