poj1190——生日蛋糕

题目大意:制作一个每层都是圆柱体,体积Nπ的M层蛋糕,下层的比上层的半径更大,高度更高,找出每层适当的Ri和Hi使得蛋糕表面积(最下一层的下底面除外)Sπ最小,求S的最小值,以上数据皆为正整数

输入:N(N <= 10000)

           M(M <= 20)

输出:S(若无解输出0)

分析:dfs+花式大剪枝

           剪枝方法如下:

           1.半径r,与高h都从N+1开始搜索。

           2.因为前level层的面积为s,如果剩下的几层的面积都取最小可能值,所得的面积和比已经得到的所求的最小面积best大,也可以进行剪枝(剪枝条件为:s+mins[dep-1]>best)

           3.因为前level层的体积为v,如果剩下的几层的体积都取最小可能值,总体积还是比n大,那么则说明前level层的方案不可行,所以可以剪枝(剪枝条件为:v+minv[dep-1]>n) 

           4.(目前体积-已有体积)/r*2+已有的表面积若大于已经得到过的S则减掉。

           /**

*2*r*h=S

* r*r*h=V

* => V*2/r = S

* S + sumS >= best => return;

*/如果把剩下的所有体积,全部用来只做成一个圆柱体,这种情况加所增加到表面积是最小的。 

代码:转载自http://blog.csdn.net/v5zsq/article/details/46575215

#include<stdio.h>
#define in(a,b) (a<b?a:b)
int n,m;
int minv[21],mins[21];
int bests;

void dfs(int v,int s,int level,int r,int h)//v为体积,s为表面积,level为搜索深度,从底层m层向上搜,r,h分别为level的上一层的半径和高度  
{
    if(level==0)//搜索完成,则更新最小面积值
    {
        if(v==n&&s<bests)
            bests=s;
        return ;
    }
    if(v+minv[level-1]>n||s+mins[level-1]>bests||2*(n-v)/r+s>=bests)//剪枝 
        return ;
    int i,j,hh;
    for(i=r-1;i>=level;i--)//按递减顺序枚举level层蛋糕半径的每一个可能值,这里第level层的半径最小值为level  
    {
        if(level==m)//底面积作为外表面积的初始值(总的上表面积,以后只需计算侧面积)
            s=i*i;
        hh=in((n-v-minv[level-1])/(i*i),h-1); //最大高度,即level层蛋糕高度的上限,(n-v-minv[level-1])表示第level层最大的体积
        for(j=hh;j>=level;j--)//同理,第level层的最小高度值为level 
            dfs(v+i*i*j,s+2*i*j,level-1,i,j);//递归搜索子状态 
    }           
}
int main()
{
    int i;
    minv[0]=0;
    mins[0]=0;
    for(i=1;i<=20;i++)//从顶层向下计算出最小体积和表面积的可能值 
    {
        //从顶层(即第一层)到第i层的最小体积minv[i]成立时第j层的半径和高度都是j 
        minv[i]=minv[i-1]+i*i*i;
        mins[i]=mins[i-1]+2*i*i;
    }
    while(scanf("%d%d",&n,&m)==2)
    {
        bests=0x7fffffff;
        dfs(0,0,m,n+1,n+1);
        if(bests==0x7fffffff)
            printf("0\n");
        else
            printf("%d\n",bests);
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值