问题:
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
(除Q外,以上所有数据皆为正整数)
Input
有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。
Output
仅一行,是一个正整数S(若无解则S = 0)。
Sample Input
100 2
Sample Output
68
Hint
圆柱公式
体积V = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
思路:
1:深搜加各种剪枝。
2:先找出来半径和高度的范围,然后从底层往上层枚举可能的表面积。
代码:
#define T 30
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int N,M,minArea,area;
int minV[T],minA[T];
//minA[i]为第i层往上,最小的总表面积
//minV[i]为第i层往上,最小的总体积
int MaxVNRH(int n,int r,int h)
{
int v=0;
for(int i=0; i<n; i++)//每层都递减1,就是能做的最大体积
v+=(r-i)*(r-i)*(h-i);
return v;
}
void dfs(int v,int n,int r,int h)
/*v:还需要做多少体积的蛋糕。
n:还需要做多少层
r:还需要做的最底层蛋糕半径不能超过多少
h:还需要做的最底层蛋糕高度不能超过多少
*/
{
if(n==0)
{
if(v)return ;
else
{
minArea=min(minArea,area);
return ;
}
}
if(minV[n]>v)return;//当还需要做的蛋糕的体积v小于了最小体积,说明底层用的体积多了
if(area+minA[n]>=minArea)return;//如果已经做好的蛋糕,加上还没做好的蛋糕的体积已经大于了以求出的最小体积,方案不可行。
if(h<n||r<n)return;//高度或半径,不能满足从上到下递减的要求。
if(MaxVNRH(n,r,h)<v)return;//在第n使,底层r和h最大是能得到的最大体积比V目标体积还小,就是不可行的
for(int i=r; i>=n; i--)
{
if(n==M)area=i*i;//把所有已做好的蛋糕上表面积投影到底面,正好是最底面的下表面积
for(int j=h; j>=n; j--)
{
area+=2*i*j;//求侧面积
dfs(v-i*i*j,n-1,i-1,j-1);
area-=2*i*j;
}
}
}
int main()
{
memset(minV,0,sizeof(minV));
memset(minA,0,sizeof(minA));
for(int i=1; i<30; i++)//求出最小总和,因为最顶层最小r=1,h=1,r,h依次往下递增,所以每一层r和h最小都是n(n表示层数)
{
minV[i]=minV[i-1]+i*i*i;
minA[i]=minA[i-1]+2*i*i;
}
while(~scanf("%d%d",&N,&M))
{
int maxH=(N-minV[M-1])/(M*M)+1; //最底层蛋糕最大高度(这是假设上面的蛋糕,依次递减到最上层时h=1的情况)
int maxR=sqrt(double(N-minV[M-1])/M)+1;//最底层蛋糕的最大半径。(最底层半径最小是M,上面蛋糕体积最小是minV[M-1],然后根据数学公式推导)
minArea=0x3f3f3f3f;
area=0;
dfs(N,M,maxR,maxH);//
if(minArea==0x3f3f3f3f)
printf("0\n");
else
printf("%d\n",minArea);
}
return 0;
}