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外,以上所有数据皆为正整数)
设从下往上数第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
体积V = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
Source
这题很显然是一道深度优先搜索题。但是更重要的部分是剪枝。
本题可以剪枝的方面主要着这些,当前情况下表面积是否最后会大于已求得的最优值。
当前情况的最后体积已大于给定值,或到不了给定值。
半径和高度大于目前的层数。
#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
int n,m,sum;
int ans=INF;
int minv[25],mina[25];
int maxss(int r,int h,int s)
{
int res=0;
for(int i=0;i<s;i++){
res+=(r-i)*(r-i)*(h-i);
}
return res;
}
int dfs(int v,int s,int r,int h)
{
if(s==0){
if(!v){
ans=min(ans,sum);
}
return 0;
}
if(r<s||h<s||minv[s]>v||sum+mina[s-1]>=ans||v<=0){
return 0;
}
if(maxss(r,h,s)<v){
return 1;
}
for(int i=r;i>=s;i--){
if(s==m){
sum=i*i;
}
for(int j=h;j>=s;j--){
sum+=2*i*j;
int temp=dfs(v-i*i*j,s-1,i-1,j-1);
sum-=2*i*j;
if(temp==1){
break;
}
}
}
return 0;
}
int main()
{
minv[0]=mina[0]=0;
for(int i=1;i<21;i++){
minv[i]=minv[i-1]+i*i*i;
mina[i]=mina[i-1]+2*i*i;
}
scanf("%d%d",&n,&m);
if(n<minv[m]){
printf("0\n");
return 0;
}
int temp=n-minv[m-1];
int maxr=(int)sqrt((temp)*1.0/m)+1;
int maxh=temp/(m*m)+1;
sum=0;
ans=INF;
dfs(n,m,maxr,maxh);
if(ans==INF){
printf("0\n");
}else{
printf("%d\n",ans);
}
return 0;
}