zoukankan      html  css  js  c++  java
  • 洛谷 P1731 [NOI1999]【生日蛋糕】

    描述

      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外,以上所有数据皆为正整数)

    输入输出格式

    输入

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

    输出

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

    输入输出样例

    输入样例1

    100
    2

    输出样例1

    68
    

    解题思路

      请见题解(有点懒)还有,枚举r和h时不知道为什么前面的要从大到小,后面的要从小到大,知道的请评论解决一下,谢谢!!!

    题解

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,m,ans;
     4 int h[11000],r[11000];//记录每个蛋糕的半径和高 
     5 int fixs[11000];//最小的蛋糕表面积(不算底面) 
     6 int fixv[11000];//最小的蛋糕体积(不算底面) 
     7 void dfs(int dep,int s,int v)//深度,面积,体积 
     8 {
     9     if(dep==m+1)//搜完了 
    10     {
    11         if(v==n)ans=min(ans,s);//如果体积一样取最优解 
    12         return ;
    13     }
    14     int qwe=min(int(sqrt(n-v)),r[dep-1]-1);//前面是假设高为一是的半径值,后面是上一个蛋糕半径减一 
    15     for(int i=qwe;i>=(m-dep+1);i--)//枚举,因为每一个蛋糕都要比前一个半径小,所以要到m-dep+1 
    16     {
    17         if(2*(n-v)/i+s>=ans)//表面积大于当前值,返回 
    18             continue;
    19         for(int j=(m-dep+1);j<=min((n-v)/(i*i),h[dep-1]-1);j++)//同理,每一个蛋糕 要比前一个蛋糕矮,而且后面是比较上一个蛋糕高减一 
    20         {//和假设这是最后一个蛋糕的最大高 
    21             if(s+2*i*j+fixs[dep+1]>=ans)//极小化剪枝,如果加上这些还是比当前最优解大,直接返回 
    22                 break;
    23             if(v+i*i*j+fixv[dep+1]>n)//极小化剪枝,如果加上这些还是比n大,直接返回 
    24                 break;
    25             r[dep]=i;
    26             h[dep]=j;//记录 
    27             if(dep!=1)dfs(dep+1,s+2*i*j,v+i*i*j);//第一次要加上底面积 
    28             else dfs(dep+1,s+2*i*j+i*i,v+i*i*j);
    29             r[dep]=0;
    30             h[dep]=0;//取消标记,回溯操作 
    31         }
    32     }
    33 }
    34 int main()
    35 {
    36     cin>>n>>m;
    37     for(int i=m;i>=1;i--)
    38     {
    39         fixs[i]=fixs[i+1]+2*(m-i+1)*(m-i+1);//最小表面积后缀和 
    40         fixv[i]=fixv[i+1]+(m-i+1)*(m-i+1)*(m-i+1);//最小体积后缀和 
    41     }
    42         
    43     ans=999999999;
    44     r[0]=999999999;
    45     h[0]=999999999;//初始化 
    46     dfs(1,0,0);
    47     if(ans==999999999)cout<<0<<endl;//没找到就输出0 
    48     else cout<<ans<<endl;
    49     return 0;
    50 }

      

  • 相关阅读:
    HTTP浅析
    PHP CURL获取cookies模拟登录
    C++ builder 通过WMI方式修改DNS
    C语言List使用样例
    C语言 获取系统临时目录并获取临时文件名
    C语言 写文件样例
    vb wmi 修改ip地址、网关、DNS
    正则表达式校验IP地址
    c语言 vector使用样例
    C++ builder 通过WMI查询网卡对应的序号
  • 原文地址:https://www.cnblogs.com/hualian/p/11165342.html
Copyright © 2011-2022 走看看