• 生日蛋糕 POJ


    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

     
    思路:正常深搜,但是会TLE,需要众多剪枝
    ①我们可以预处理1~当前层所需的最小表面积和体积,然后如果已经选的表面积(体积)+ 剩下最小表面积(体积)超过ans(N规定体积)就return
    ②枚举r,h时,我们可以知道规定枚举范围,就不需要每次减一递减
    maxR = min(r,sqrt(N-SumV-minV[now-1])
    maxH = min(h,(n-SumV-minV[now-1])/(i*i))
    ③最难的一个剪枝:
    n-SumV = Σh【k】*r【k】*r【k】   (1<=k<=now)               
    2*Σr【k】*h【k】= 2/r【now+1】*Σr【k】*h【k】*r【now+1】 >=  2/r【now+1】*Σh【k】*r【k】*r【k】(1<=k<=now)
    2*Σr【k】*h【k】 >= 2*(n-SumV)/r【now+1】  (1 <= k <= n)
    所以 SumS + = 2*(n-SumV)/r【now+1】 >= ans 就return
    因为当前dfs的r,h是本次选择的时候的边界,所以加个last变量记录r【now+1】即上次选择的半径r
     
    #include<cstdio>
    #include<cstdio>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    
    int n,m,ans;
    int minV[22];
    int minS[22];
    void dfs(int now,int SumS,int SumV,int r,int h,int last)
    {
        if(SumS + minS[now] > ans)
            return;
        if(SumV + minV[now] > n)
            return;
        if(SumS + 2*(n-SumV)/last >= ans)
            return;
        if(!now)
        {
            if(SumV == n && SumS < ans)
                ans = SumS;
            return;
        }
        int maxR = min(r,(int)sqrt(n-SumV-minV[now-1]));
        for(int i=maxR;i>=now;i--)
        {
            if(now == m)SumS = i*i;
            int maxH = min((n-minV[now-1]-SumV)/(i*i), h);
            for(int j=maxH;j>=now;j--)
            {
                dfs(now-1,SumS+2*i*j,SumV+i*i*j,i-1,j-1,r);
            }
        }
    }
    
    int main()
    {
        ans = 0x3f3f3f3f;
        for(int i=1; i<=18; i++)
        {
            minV[i] += minV[i-1] + i*i*i;
            minS[i] += minS[i-1] + 2*i*i;
        }
        scanf("%d%d",&n,&m);
        dfs(m,0,0,100,10000,200);
        if(ans == 0x3f3f3f3f)ans = 0;
        printf("%d
    ",ans);
    }
    View Code
     
     
     
  • 相关阅读:
    设计模式总结——程序猿的武功秘籍(上)
    php获取分类以下的全部子类方法
    TypeError: Cannot read property &#39;style&#39; of null 错误解决
    Java抽象类
    PHP_SELF、 SCRIPT_NAME、 REQUEST_URI差别
    [WPF]使用Pack URI路径訪问二进制资源
    Android JNI编程(五)——C语言的静态内存分配、动态内存分配、动态创建数组
    Android JNI编程(四)——C语言多级指针、数组取值、从控制台输入数组
    Android JNI编程(三)——C语言指针的初步认识、指针变量、互换两个数、函数返回多个值
    Android JNI编程(二)——C语言的基本数据类型,输出函数,输入函数
  • 原文地址:https://www.cnblogs.com/iwannabe/p/10581693.html
Copyright © 2020-2023  润新知