
【题意】
制作一个体积为N π的M 层生日蛋糕,每层都是一个圆柱体。设从下往上数第i (1≤i ≤M )层蛋糕是半径为Ri 、高度为Hi 的圆柱。当i
令Q =S π,对给出的N 和M ,找出蛋糕的制作方案(适当的Ri 和Hi 的值),使S 最小。除Q 外,以上所有数据皆为正整数。
【输入输出】
输入:
输入包含两行,第1行为N (N ≤10 000),表示制作的蛋糕的体积为N π;第2行为M (M ≤20),表示蛋糕的层数。
输出:
单行输出一个正整数S (若无解,则S =0)。
【样例】

圆柱体积V =πR^2 H ,侧面积A '=2πRH ,底面积A =πR。
【思路分析】
这道题为在体积和层数一定的情况下,找到合适的半径和高度,使蛋糕表面积最小。可以采用回溯法搜索求解。
① 预处理
从顶层向下计算出最小体积和面积的最小可能值。在从顶层(即第1层)到第i 层的最小体积minv [i ]成立时,第i 层的半径和高度都为i 。此时只计算侧面积,对上表面积只在底层计算一次,底层的底面积即总的上表面积。
void init(){
minv[0] = mins[0] = 0;
for(int i = 1; i < 22 ; i++){
minv[i] = minv[i - 1] + i * i * i;
mins[i] = mins[i - 1] + 2 * i * i;
}
}
【算法设计】
dep指当前深度;sumv、sums分别指当前体积和、面积和;r 、h分别指当前层半径、高度。
① 从底层m 层向上搜,当dep=0时,搜索完成,更新最小面积。
② 剪枝技巧
③ 枚举半径i ,按递减顺序枚举dep层蛋糕半径的每一个可能值i ,第dep层的半径最小值为dep。
【算法实现】
#include
#include
using namespace std;
const int N=30;
const int inf=0x3f3f3f3f;
int n,m,minv[N],mins[N],best;
void init(){
minv[0]=mins[0]=0;
for(int i=1;i<22;i++){
minv[i]=minv[i-1]+i*i*i;
mins[i]=mins[i-1]+2*i*i;
}
}
void dfs(int dep,int sumv,int sums,int r,int h){
if(!dep){
if(sumv==n&&sums<best) best=sums;
return ;
}
if(sumv+minv[dep]>n||sums+mins[dep]>best||sums+2*(n-sumv)/r>best)
return;
for(int i=r;i>=dep;i--){
if(dep==m) sums=i*i;
int maxh=min((n-sumv-minv[dep-1])/(i*i),h);
for(int j=maxh;j>=dep;j--)
dfs(dep-1,sumv+i*i*j,sums+2*i*j,i-1,j-1);
}
}
int main(){
init();
while(~scanf("%d%d",&n,&m)){
best=inf;
dfs(m,0,0,n,n);
printf("%d\n",best==inf?0:best);
}
return 0;
}
