塔
又是一个思路很奇妙的题(最近我看什么DP题都觉得很奇妙)。
先看题:
洛谷P1651 塔
题目描述
小明很喜欢摆积木,现在他正在玩的积木是由 N 个木块组成的,他想用这些木块搭出两座高度相同的塔,一座塔的高度是搭建它的所有木块的高度和,并且一座塔至少要用一个木块。每个木块只能用一次,也可以不用。目前已知每块木块的高度,小明想知道在最终两个塔的高度相同的情况下,他所能搭的塔的最大高度是多少,你能帮助他吗?
输入格式
第一行为一个整数 N,表示木块个数。
第二行是 N 个整数,表示 N 块木块的高度。
输出格式
仅一个整数,表示能搭建的塔的最大高度,若不能搭建两座相同高度的塔,则输出 -1
。
输入输出样例
输入 #1
3 2 3 5
输出 #1
5
说明/提示
对于 100% 的数据,N≤50 ,每块木块的高度 h 满足 1≤h≤500000,所有木块的高度总和 ≤500000。
我是用了一个结构体:
struct node{ int a,b;//a是两塔中较高的塔的高度,b是另一个塔的高度。 bool p;//p表示两塔高度差能不能为i。 }f[500010];//f[i]中i是两塔高度差。
i从1到n,放第i块积木,放每一块积木最多有三种可能情况:
1.积木放在a塔。
2.积木放在b塔,但b塔高度超不过a塔。
3.积木放在b塔,且b塔高度会超过a塔。(a、b塔要交换位置)
枚举新的塔的高度差,是由之前的哪种情况得到,求a塔最高值,在将这一轮的和总的进行比较,所有的都取a塔的更大值。
最后看f[0].a是否有高度,有则输出f[0].a,否则输出-1。
下面是代码:
#include<iostream> using namespace std; int n; int h[60]; struct node{ int a,b; bool p; }f[500010],t[500010]; int qian[500010]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>h[i]; qian[i]=qian[i-1]+h[i]; } f[0].p=1; for(int i=1;i<=n;i++){ for(int j=0;j<=qian[i];j++){ if(h[i]>j){ if(f[h[i]-j].p){ t[j].a=f[h[i]-j].b+h[i]; t[j].b=f[h[i]-j].a; t[j].p=1; } } else{ if(f[j-h[i]].p){ t[j].a=f[j-h[i]].a+h[i]; t[j].b=f[j-h[i]].b; t[j].p=1; } } if(f[j+h[i]].p){ if(t[j].p==0){ t[j].a=f[j+h[i]].a; t[j].b=f[j+h[i]].b+h[i]; t[j].p=1; } else if(t[j].a<f[j+h[i]].a){ t[j].a=f[j+h[i]].a; t[j].b=f[j+h[i]].b+h[i]; t[j].p=1; } } } for(int j=0;j<=qian[i];j++){ if(t[j].a>f[j].a&&t[j].p){ f[j]=t[j]; } t[j].p=0; } } if(f[0].a==0){ cout<<-1; return 0; } cout<<f[0].a; return 0; }