題目傳送門: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;
}