ACWing168生日蛋糕(搜索剪枝)

題目傳送門:https://www.acwing.com/problem/content/170/
題目大意:
給定蛋糕的體積和層數,要再此蛋糕的表面抹奶油,要想奶油成本最低,如何建這個M層的蛋糕。
分析:
此題是一個典型的搜索題,因爲找不到遞推式,或者貪心,或者分治等算法的思路。當走投無路時,試試搜索吧。那麼搜可按蛋糕的底層開始,逐層搜索到頂層,到了頂層m層再維護一個表面積最大。但是這個搜索狀態可多了,如何剪枝,去掉不可能的解就是非常重要的了。可以從以下幾個方面考慮(截圖於ACwing上VMice的題解,全文題解網址鏈接:https://www.acwing.com/solution/AcWing/content/1500/):
在這裏插入圖片描述那麼附上代碼:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 20+6;
const int INF = 1000000000;
int n,m,mins[MAXN],minv[MAXN],ans = INF,r[MAXN],h[MAXN];
void dfs(int dep,int s,int v)//dep表示正在處理第dep層,s表示已經有的表面積,v表示已經由的體積。
{
	 if(dep == 0) {
	 	if(v == n) ans = min(ans, s);//當到了目標狀態時維護最小值。
	 }	 
	 else{
	 	for(int ri = min((int)(sqrt(n-v)) , r[dep+1] - 1); ri>= dep; ri --){
	 		for(int hi = min((int)((n-v)/(1.0*(ri * ri))),h[dep+1] - 1); hi>= dep; hi--){
	 			r[dep] = ri;
	 			h[dep] = hi;
	 			//當已經產生的表面積加上還沒有做成的層數中最少的表面積都比ans大則此分支不可能有最優解,剪去。 
				 if(s + mins[dep] > ans) continue;
				 //當已經產生的體積加上還沒有做成的層數中最小的體積都比n要大,則此分支不可行,剪掉。 
				 if(v + minv[dep] > n)continue; 
				 //數學分析進行最優性剪枝(此剪枝比較難想到。)
				 if(s + 2.0*(n-v)/ri > ans) continue;
				 if(dep == m) s = ri * ri;//當在最底層時加上底面的圓面積。
				 dfs(dep - 1, s + 2 * ri * hi, v + ri * ri * hi) ;
				 if(dep == m) s = 0;
	 		}
	 	}
	 } 
} 
int main(){
	cin >> n >> m;
	//從上往下用最小的半徑和最小的高度來作爲從頂端到第i層的最小表面積和最小體積。 
	//供後面可行性剪枝用。 
	for(int i = 1;i<= m; i++){
		mins[i] = mins[i - 1] + 2 * i * i;
		minv[i] = minv[i - 1] + i * i * i; 
	}
	r[ m+1 ] = h[m+1] = INF;
	dfs(m , 0 , 0); 
	if(ans == INF) cout << 0;
	else cout << ans ; 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章