P1651

题目描述

小明很喜欢摆积木,现在他正在玩的积木是由 \(N\) 个木块组成的,他想用这些木块搭出两座高度相同的塔,一座塔的高度是搭建它的所有木块的高度和,并且一座塔至少要用一个木块。每个木块只能用一次,也可以不用。目前已知每块木块的高度,小明想知道在最终两个塔的高度相同的情况下,他所能搭的塔的最大高度是多少,你能帮助他吗?

输入格式

第一行为一个整数 \(N\),表示木块个数。

第二行是 \(N\) 个整数,表示 \(N\) 块木块的高度。

输出格式

仅一个整数,表示能搭建的塔的最大高度,若不能搭建两座相同高度的塔,则输出 -1

样例 #1

样例输入 #1

3
2 3 5

样例输出 #1

5

提示

对于 \(100\%\) 的数据,\(N \le 50\) ,每块木块的高度 \(h\) 满足 \(1 \le h \le 500000\),所有木块的高度总和 \(\le 500000\)

绝好的一道DP题!
开始用的bool pack
假做法还得了80pts  因为这种没办法保证 h和h/2用的不重复
神奇正解
f[i][j]:前i个 差值为j(>0)时较高塔的高度
则有以下状态转移:
1.ith不放
2.ith放较高的
3.ith放较低的但是仍较低
4.ith放较低的但变成了较高的
(这种不看题解谁TM会啊~)
还有个细节:最开始f要赋-INF(我也不知道为什么)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
int n,a[55],f[55][500005],h;//放了前i个 差值为j 的最大高度 
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],h+=a[i];
	memset(f,-0x3f,sizeof(f));
//	cout<<f[0][0]<<' ';
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=h;j++)
		{
			f[i][j]=max(f[i-1][j],f[i-1][j+a[i]]);
			if(j-a[i]>=0)f[i][j]=max(f[i][j],f[i-1][j-a[i]]+a[i]);
			else f[i][j]=max(f[i][j],f[i-1][a[i]-j]+j);
		}
	}
	if(f[n][0]>0)cout<<f[n][0]<<"\n";
	else cout<<-1<<"\n";
	
	return 0;
}
posted @ 2023-01-13 14:49  PKU_IMCOMING  阅读(12)  评论(0)    收藏  举报