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
题意:给定了蛋糕的层数和体积,最底层的半径和高度最大,越往上半径和高度越小,问应该怎样制作这个蛋糕使涂奶油的部分面积最小(即蛋糕表面积最小)输出这个最小表面积。
思路:这个题不是那么好做,是一道深搜题,但是起点好像无处着手,仔细想想如果从上至下第i层半径为i高度为i的话,求出上面n-1层的体积,那么最底层的高度和半径就可以求出来了,就从这个最底层的最大高度和半径着手开始深搜,从下至上枚举每一层可能的高度还有半径。因为深搜容易超时,这个题尤其注意得剪枝,搭建过程中发现已建好的面积已经超过目前求得的最优表面积 ,或者预见到搭完后面积一定会超过目前最优表面积,则停止搭建return,搭建过程中发现剩余可搭建的体积小于0了,则return,搭建过程中发现还没搭的那些层的体积最大也到不了还缺的体积,则return,搭建过程中发现某一层的半径或高度不合理了(比那一层搭建的下限还要小)则return,一定要注意好这些剪枝,代码如下:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define inf 99999999
int minS[30];
int minV[30];
int minss,M,N,ss;
int angel2(int n,int r,int h)
{
//求在n层蛋糕,底层最大半径r,最高高度h的情况下,能凑出来的最大体积
int v = 0;
for( int i = 0; i < n ; ++ i )
v += (r - i ) *(r-i) * (h-i);
return v;
}
void angel(int v,int n,int r,int h)
{
if(n==0) //n层蛋糕遍历完了
{
if(v!=0) //但是体积不为0
return ;
else
{
minss=min(minss,ss);
return ;
}
}
if(v<=0)
return ;
if(minV[n]>v)//估算n层蛋糕体积最小值都大于v了
return ;
if(ss+minS[n]>=minss) //估算n层蛋糕表面积最小值大于当前的最优表面积
return ;
if(h<n||r<n)//如果 高和半径小于n(n是最小的高和半径)
return ;
if(angel2(n,r,h)<v) //求n层凑出来整体的最大体积都小于v
return ;
for(int rr=r; rr>=n; rr--)
{
if(n==N)
ss=rr*rr; //底面积
for(int hh=h; hh>=n; hh--)
{
ss=ss+2*rr*hh;
angel(v-rr*rr*hh,n-1,rr-1,hh-1);
ss=ss-2*rr*hh;
}
}
return ;
}
int main()
{
scanf("%d %d",&M,&N);//体积为M,层数为N
minS[0]=0;
minV[0]=0;
for(int i=1; i<=N; i++)
{
minV[i]=minV[i-1]+i*i*i;//从上到下i层蛋糕体积的最小值 pai 舍弃不要了
minS[i]=minS[i-1]+2*i*i;//从上到下i层蛋糕侧面积的最大值 ,pai舍弃不要了
}
int maxH=(M-minV[N-1])/(N*N)+1;
int maxR=sqrt((M-minV[N-1]+0.0)/N)+1;
if(minV[N]>M) //当蛋糕体积的最小值都大于M
printf("0\n");
else
{
ss=0;
minss=inf;
angel(M,N,maxR,maxH);
if(minss==inf)
printf("***0\n");
else
printf("%d\n",minss);
}
return 0;
}