生日蛋糕 POJ - 1190

问题:

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

猜你喜欢

转载自blog.csdn.net/lxxdong/article/details/81222345