洛谷 P1651 塔
题目传送门
一道dp,但我没推出方程,只好写记忆化搜索+剪枝.
主要说一下为什么从小到大排序,如果大的块被选择且最终得出符合题意的答案,那么后面很多状态都会被剪掉,因为答案越搜越小(应该是).
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
int n,h[51],ans = -1,sum[51];
map<int,map<int,map<int,bool> > > s;
inline int max(int a,int b) {
if(a > b) return a;
return b;
}
inline void dfs(int d,int lena,int lenb) {
if(d == n + 1) {
if(lena == lenb && lena != 0) ans = max(lena,ans);
return ;
}
if(s[d][lena][lenb] == 1) return ;
s[d][lena][lenb] = 1;
if(lena > sum[n] / 2) return ;
if(lenb > sum[n] / 2) return ;
if(lena + sum[n] - sum[d-1] < lenb) return ;
if(lenb + sum[n] - sum[d-1] < lena) return ;
if(lena + sum[n] - sum[d-1] == lenb && lenb != 0) {
ans = max(ans,lenb);
return ;
}
if(lenb + sum[n] - sum[d-1] == lena && lena != 0) {
ans = max(ans,lena);
return ;
}
if(ans >= lena + sum[n] - sum[d-1]) return ;
if(ans >= lenb + sum[n] - sum[d-1]) return ;
if(ans * 2 >= lena + lenb + sum[n] - sum[d-1]) return ;
dfs(d + 1,lena,lenb + h[d]);
dfs(d + 1,lena + h[d],lenb);
dfs(d + 1,lena,lenb);
return ;
}
inline bool cmp(int a,int b) {
return a > b;
}
int main() {
scanf("%d",&n);
for(int i = 1;i <= n; i++)
scanf("%d",&h[i]);
sort(h+1,h+n+1,cmp);
for(int i = 1;i <= n; i++)
sum[i] += sum[i-1] + h[i];
dfs(1,0,0);
printf("%d",ans);
return 0;
}