洛谷 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章