生日蛋糕

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

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值