zoukankan      html  css  js  c++  java
  • 1710 生日蛋糕(1999 noi)

    1710 生日蛋糕(1999 noi)

     1999年NOI全国竞赛

    题目描述 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 Description

    有两行,第一行为N(N<=10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=20),表示蛋糕的层数为M。

    输出描述 Output Description

    仅一行,是一个正整数S(若无解则S=0)。

    样例输入 Sample Input

    100   2

    样例输出 Sample Output

    68

    数据范围及提示 Data Size & Hint

    体积V=πR2H

    侧面积A’=2πRH

    底面积A=πR2

    题目分析:搜索题,其实不减枝的代码还是很好写的。

    参考程序:

    #include<stdio.h>

    #include<string.h>

    #define maxn 22

    #define INF 100000000

     

    int N,M,ans,maxh;

    //m为蛋糕的层数, v为当前的体积, s为当前得到的面积,r和h为当前层的半径和高

    void dfs(int m,int v,int s,int r,int h){

        //退出条件

        if(m == 0){

            if(ans > s && v == N) ans = s;

            return;

        }

        //枚举可能的解

        for(int i = r-1; i >= m; i--){

            for(int j = maxh; j >= m; j--){

                if(m == M) s = i * i;

                dfs(m-1,v+i*i*j,s+2*i*j,i,j);

            }

        }

    }

     

    int main(){

        scanf("%d%d",&N,&M);

        ans = INF;

        maxh=N/M/M;//唯一的剪枝,底层蛋糕的最大高度N/(M*M)

        dfs(M,0,0,N+1,N+1);

        if(ans == INF) printf("0 ");

        else printf("%d ",ans);

        return 0;

    }

    然后就是剪枝呢,四个减枝的条件:

        先打表,算出每层蛋糕的最小体积和表面积(minv[i]和mins[i]),然后在来减枝

        1、v+minv[m]  > V

                v为已经涂的体积,那么如果v加上下一层最小的体积比总体积V还大,这显然是不可能的,减去。

        2、s+min[m] > ans

                s为已经涂的面积,那么s加上下一次最小的面积比当前求得的ans还大,显然不需要dfs了,减去。

        3、2*(V-v)/r + s >= ans

               已经涂了s,那么还剩下rest_s = sum{2*Ri*Hi} >= sum{2*Ri*Ri*Hi/Rk} = 2*(V-v)/r (设k为当前层的半径)。如果rest_s加上s大于等于ans,那么也不用在dfs了。

        4、maxh = Min((N-v-minv[m-1])/(i*i),h-1)

               当枚举半径为i时,当前最低的可能高为maxh = Min((N-v-minv[m-1])/(i*i),h-1)。

    剪枝后的代码:

    //注意:本程序蛋糕自顶向下编号(与题目相反),dfs由下向上运行.

    #include<iostream>

    #include<cmath>

    using namespace std;

    const int INF=1000000;

    const int Size=22;

    int N,M;

    int ans;

    int mins[Size],minv[Size];

    int maxh;

    void init(){

          mins[0]=minv[0]=0;

          for(int i=1;i<=M;i++){

                 mins[i]=mins[i-1]+2*i*i;

                 minv[i]=minv[i-1]+i*i*i;

          }

    }

    void dfs(int m,int v,int s,int lastr,int lasth){

          //cout<<m<<' ';

          if(m==0){

                 if(v==N)ans=min(ans,s);

                 return;

          }

          if(v+minv[m]>N)return;

          if(s+mins[m]>=ans)return;

          if(2*(N-v)/lastr+s>=ans)return;

          for(int r=lastr-1;r>=m;r--){

                 int maxh=min((N-v-minv[m-1])/(r*r),lasth-1);//注意这里是minv[m-1],因为 总体积N – 已经有的v – 将要有的最小体积minv[m+1]  才是 m这一层的最大体积,进而计算最大高度

                 //cout<<maxh<<endl;

                 for(int h=maxh;h>=m;h--){

                        if(m==M)s=r*r;//整个蛋糕与桌面向平的那些环面的面积之和==底层蛋糕的圆面的面积,在此加上

                        dfs(m-1,v+r*r*h,s+2*r*h,r,h);

                 }

          }

    }

    int main(){

          freopen("1.in","r",stdin);

          cin>>N>>M;

          ans=INF;

          maxh=N/M/M;

          init();

          int maxr=sqrt(N);

          dfs(M,0,0,maxr+1,N+1);

          cout<<ans<<endl;

          return 0;

    }

  • 相关阅读:
    真实的人类第三季/全集Humans迅雷下载
    明日传奇第三季/全集Legends of Tomorrow迅雷下载
    怪奇物语第二季/全集Stranger Things迅雷下载
    行尸走肉第八季/全集The Walking Dead迅雷下载
    暗影猎人第一二季/全集Shadowhunters迅雷下载
    史上十大很黄很暴力的美剧
    蓝精灵:寻找神秘村Smurfs: The Lost Village迅雷下载
    神奇女侠Wonder Woman迅雷下载
    冰川时代5:星际碰撞Ice Age: Collision Course迅雷下载
    mysql慢查询监控及sql优化
  • 原文地址:https://www.cnblogs.com/FuTaimeng/p/5594459.html
Copyright © 2011-2022 走看看