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