POJ 1190 - 生日蛋糕

28 篇文章 0 订阅

Description

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
题意:难得的中文题,给出蛋糕体积和层数,求出最小的表面积。
因为π都省略了,所以可以直接用正整数来计算。首先这是一道 深搜+剪枝的题目,面积可以用 r*r 来计算,体积可以用 r*r*h 来计算。
看了大神的博客才知道剪枝的条件,简直是神剪枝。

三个剪枝是:

1.总体积减去蛋糕当前层以下的层的总体积是否小于上面的层所能构成的最小体积。如果小于则返回。

2.已算得的答案(最小面积)减去蛋糕当前层以下的层的总面积是否小于上面的层所能构成的最小面积。如果小于则返回。

3.设剩余总体积为总体积减去蛋糕下面的层的总体积,剩余总面积是当前已得最优解减去蛋糕当前层以下的层的总面积。设ri为每层的半径,hi为每层的高度。蛋糕上面层的总面积是对2*ri*hi求和。总体积ri*ri*hi求和。剩余总体积*2再除以当前层的半径必须小于剩余总面积,否则返回。(2×sigma(ri*ri*hi)/rk > sigma(2*ri*hi) i=1~k)之所以左边大于右边是因为rk>ri  对于i<k。

#include <cstdio>
#include <cmath>

const int INF = 0x3f3f3f3f;
int ans;
int layer, tot_v;
int min_v[25], min_s[25];

void DFS(int s, int v, int n, int max_r, int max_h)
{
    if (n == 0)
    {
        if (v != tot_v)
            return;
        ans = ans < s ? ans : s;
        return;
    }
    if (tot_v - v < min_v[n])
        return;
    if (ans - s < min_s[n])
        return;
    if (n < layer && ans - s < 2 * (tot_v - v) / max_r)
        return;
    for (int i = max_r; i >= n; --i)
    {
        if (n == layer)
            s = i*i;
        int h = (tot_v - min_v[n-1] - v) / (i*i);///calculate the high
        for (int j = h < max_h ? h : max_h; j >= n; --j)
            DFS(s + 2*i*j, v + i*i*j, n - 1, i - 1, j - 1);
    }
}

int main()
{
     while (scanf("%d%d", &tot_v, &layer) != EOF)
     {
         ans = INF;
         min_s[0] = 0;
         min_v[0] = 0;
         for (int i = 1; i < 25; ++i)
         {
             min_s[i] = min_s[i - 1] + 2 * i * i;
             min_v[i] = min_v[i - 1] + i * i * i;
         }
         DFS(0, 0, layer, sqrt(tot_v), tot_v);
         printf("%d\n", ans);
     }
     return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值