设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
(除Q外,以上所有数据皆为正整数)
Input
Output
Sample Input
100 2
Sample Output
68
Hint
体积V = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
#include <iostream> #include <cmath> using namespace std; int n,m,minv[21],mins[21]; //V=n*pi m 层数 自顶向下1.2.3...m //minv[i]表示i层到0层加起来的最小总体积 minvs 最小表面积 const int inf=1000000000; // inf 足够大就可以 int(32) -2^31~2^31-1=2147483647 int best=inf; //best 最小表面积 void DFS(int depth,int sumv,int sums,int r,int h) //深度优先搜索 自底m向上搜索 r h表示当前层得半径和高度 //sumv已经用的总体积 sums已经生成的总表面积 { if(0==depth) { if(sumv==n&&sums<best) //搜索完成 更新最小表面积best { best=sums; } return; } // 三个剪枝条件: //1、已经搜索过的体积加上还未搜索过的最小体积不能比总体积n 大 //2、已经搜索过的表面积加上还未搜索过的最小表面积不能比之前的最小总表面积best 大 //3、n-sumv既所剩体积记作dv 还需要的表面积为s //s=2*ri*hi+2*r(i-1)*h(i-1)+... >=2*ri*hi*ri/r+2*r(i-1)*h(i-1)*r(i-1)/r+... // =2*dv/r(i从depth-1取,r为当前半径 ri/r<1) // 所以得到还需要的最小表面积s=2*(n-sumv)/r,如果最小的s和已经搜索过的表面积sums依然比best大 就不用继续搜索了 if(sumv+minv[depth-1]>n||sums+mins[depth-1]>best||sums+2*(n-sumv)/r>=best) //剪枝如上所述 return; for( int i=r-1;i>=depth;i--) //递减顺序枚举depth层半径的每一个可能值,这里第depth层的半径最小值为depth { if(depth==m) sums=i*i; //俯视蛋糕底面积作为外表面积的初始值(总的上表面积,以后只需计算侧面积) int maxh=min((n-sumv-minv[depth-1])/(i*i),h-1); //maxh最大高度,即depth层蛋糕高度的上限,(n-sumv-minv[dep-1])表示第depth层最大的体积 for(int j=maxh;j>=depth;j--) //同理,第depth层的最小高度值为depth { DFS(depth-1,sumv+i*i*j,sums+2*i*j,i,j); //递归搜索子状态 } } } int main(void) { //cout<<"input V <=10000 :"<<endl; cin>>n; //cout<<"input M <=20 :"<<endl; cin>>m; int rmax=(int)sqrt((double)n); //rmax初始半径 底层半径 最大值为sqrt(n) int hmax=n; //hmax初始高度 高度最大为 n minv[0]=mins[0]=0; for(int i=1;i<=m;i++) { //初始化minv和mins数组 minv[i]=minv[i-1]+i*i*i; //从顶层(即第1层)到第i层的最小体积minv[i]成立时第j层的半径和高度都为j mins[i]=mins[i-1]+2*i*i; } DFS(m,0,0,rmax,hmax); //DFS(m,0,0,n+1,n+1); if(best==inf) best=0; //无解 if(best==0) cout<<"0"<<endl; else cout<< best <<endl; return 0; }
2018-11-29