题目大意:自行参考
题解:
这个题非常适合初学者思考!!!
建议不要看题解,先想一想基本方法,在一步步优化。
好我开始说。
我们先只考虑“能否达到”的问题(因为一开始我是从ppt上看的,ppt上没有说让你求最大高度)。
首先第一眼是不是01背包可行性问题?
然后发现这有个问题,就是你并不能保证每个物品最多只用来建了一座塔,想想为啥。
然后改成dp[n][m1][m2]表示两个塔分别高m1m2。
复杂度O(n*m^2)显然会TLE。
然后,显然算法瓶颈在于状态繁杂,所以考虑把m1m2合并。(因为n显然是合并不了的,而且m1m2又这么像)
然后就不会做了,我就想能不能从状态转移方程入手,结果突然想到,如果m1m2的差就是当前的hi那么不就好了么?!
换句话说我们并不关心他们具体的值而只是关心他们的差!
然后一个小小的处理就是m1-m2可能是个负数,但是显然有|m1-m2|<=sigma{hi}(记作M)
所以用dp[n][m]表示m1-m2+M=m的情况。
则m1=m2即m=M。
转移就是dp[n][m]等于dp[n-1][m-h[i]] | dp[n-1][m+h[i]] | dp[n-1][m]。
初始dp[0][m]=true,其它=false。
然后就去看题发现还要求高度。
那也很好办啊,让dp[n][m]表示当前情况下两塔的高度之和是多少(显然如果知道了两塔的高度之和差就可以确定两塔高度)。
并且用-1来表示不存在(也就是之前的false)
那么转移就再加一句if(from>=0)即可。由于是和,所以最后输出要/2。
就这。
代码:
//
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 110
#define MAXM 4100
using namespace std;
int dp[MAXN][MAXM],h[MAXN];
int main()
{
int n,m=0;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
m+=h[i];
}
for(int i=0;i<=2*m;i++)
dp[0][i]=-1;
dp[0][m]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=2*m;j++)
{
dp[i][j]=-1;
if(j-h[i]>=0&&dp[i-1][j-h[i]]>=0) dp[i][j]=max(dp[i][j],dp[i-1][j-h[i]]+h[i]);
if(j+h[i]<=2*m&&dp[i-1][j+h[i]]>=0) dp[i][j]=max(dp[i][j],dp[i-1][j+h[i]]+h[i]);
if(dp[i-1][j]>=0) dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
// for(int i=1;i<=n;i++,printf("\n"))
// for(int j=0;j<=2*m;j++)
// printf("%d ",dp[i][j]);
if(dp[n][m]>0) printf("%d\n",dp[n][m]/2);
else printf("Impossible\n");
}