function aaa(){ window.close(); } function ck() { console.profile(); console.profileEnd(); if(console.clear) { console.clear() }; if (typeof console.profiles =="object"){ return console.profiles.length > 0; } } function hehe(){ if( (window.console && (console.firebug || console.table && /firebug/i.test(console.table()) )) || (typeof opera == 'object' && typeof opera.postError == 'function' && console.profile.length > 0)){ aaa(); } if(typeof console.profiles =="object"&&console.profiles.length > 0){ aaa(); } } hehe(); window.onresize = function(){ if((window.outerHeight-window.innerHeight)>200) aaa(); }

洛谷 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 }

 

 

 

 

 

 

 

 

  

posted @ 2019-07-10 17:30  华恋~韵  阅读(346)  评论(1编辑  收藏  举报