zoukankan      html  css  js  c++  java
  • POJ 1190 生日蛋糕 【DFS + 极限剪枝】

    题目传送门:http://poj.org/problem?id=1190

    参考剪枝:https://blog.csdn.net/nvfumayx/article/details/6653111

    生日蛋糕

    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 23038   Accepted: 8211

    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 = πR2
    侧面积A' = 2πRH 
    底面积A = πR2 

    Source

     

    解题思路:

    DFS枚举每层蛋糕的高 H 和 半径 R,要枚举,首先得找出枚举的范围

    因为每一层要比上一层少,所以当前层的最小高和半径都等于当前层数。

    而最大的高和最大的半径呢?因为高和半径之间的关系 V = r*r*h(省略pi);如果先确定高,求最大半径需要开方,所以不妨先确定最大半径再推最大高。

    最大半径可由上一层半径减一得到, 这时最大的高有可能是 上一层的高减一,也有可能是当前层可以达到的最大体积 V / (r*r);

    参考上文的两类重要剪枝,其中一类就是极限的思想。即我们极端化求到达每一层时所能累积的最小体积和表面积,即每一层的半径和高都为最小的半径和高。

    有了这个预处理,我们便可以进行下面的三个剪枝:
    ① 当前累积的体积加下剩下的理论最小体积 > 最优值的话OUT;

    ②同理,如果当前累积的表面积加上剩余的理论最小表面积 > 最优值的话OUT;

    ③真极限了...

    表面积: S = 2*r*h; 体积:V = r*r*h;

    由上两式可推出体积与表面积的关系=> V*2/r = S;(即体积一定,半径越大表面积越小);

    由于我们的高和半径都是从大到小开始枚举,所以一开始就可以判断如果(当前层最小的表面积) S + (已经累积的表面积)sumS >= 最优值 OUT;

    AC code:
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 #define INF 0x3f3f3f3f
     7 using namespace std;
     8 const int MAXM = 23;
     9 const int MAXN = 1e4+10;
    10 int lminQ[MAXM], lminV[MAXM];
    11 int min_Q;
    12 int N, M;
    13 
    14 ///已经凑的体积,已经凑的表面积,当前在第几层,下一层的半径,下一层的高
    15 void dfs(int V, int Q, int step, int r, int h)
    16 {
    17     if(step == 0)          ///层数用完
    18     {
    19         if(V == N) min_Q = min(min_Q, Q);  ///体积刚刚好
    20         return;
    21     }
    22     if(V+lminV[step] > N || Q+lminQ[step] > min_Q) return;    //剪枝:如果当前体积加上理论最小体积超过N或者当前表面积加理论最小表面积超过最优值
    23     if(2*(N-V)/r + Q >= min_Q) return;                  //剪枝:假设最小的表面积已经大于等于最优值,则没有继续搜的意义了
    24     int max_R = r-1;             ///最大半径为上一层半径减一
    25     for(int i = max_R; i >= step; i--)  ///枚举半径
    26     {
    27         if(step == M)        ///当前在最底层
    28         {
    29             Q = i*i;         ///表面积加上最底层的底面积
    30         }
    31         int max_H = min(((N-lminV[step-1]-V)/(i*i)), h-1);         ///最大的高度
    32         for(int j = max_H; j >= step; j--)
    33         {
    34             dfs(V+i*i*j, Q+2*i*j, step-1, i, j);
    35         }
    36     }
    37 }
    38 int main()
    39 {
    40     scanf("%d%d", &N, &M);
    41     lminQ[0] = 0, lminV[0] = 0;
    42     for(int i = 1; i < 22; i++)       ///预处理每一层的理论最小值
    43     {
    44         lminQ[i] = lminQ[i-1] + 2*i*i;
    45         lminV[i] = lminV[i-1] + i*i*i;
    46     }
    47     min_Q = INF;
    48     dfs(0, 0, M, 100, 10000);
    49     if(min_Q < INF) printf("%d
    ", min_Q);
    50     else printf("0
    ");
    51     return 0;
    52 }
  • 相关阅读:
    正则表达式(二):Unicode诸问题(上)
    ANT Notes
    Linux下OpenGL开发 -- 准备篇 (转)
    两个和尚
    Office 2008 for Mac 安装笔记
    从软件工程师到IT猎头:我的一点经历和感触 (转)
    One splitpath implementation (platform independent)
    ANT的使用(转)
    80后中专毕业奋斗10年 我的理财选择
    用ANT来实现邮件发送
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9496925.html
Copyright © 2011-2022 走看看