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;
}