生日蛋糕 深搜+剪枝

来源:互联网 发布:塞班版读书软件 编辑:程序博客网 时间:2024/05/22 12:56
生日蛋糕
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%lld & %llu
Submit Status

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

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

Output

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

Sample Input

1002

Sample Output

68

Hint

圆柱公式 
体积V = πR 2
侧面积A' = 2πRH 
底面积A = πR 2 

借鉴了poj 里面discuss的思路

其中有三个重要的剪枝
sums + mins[deep]> best 表示以前的到的deep + 1层到 m 层的表面积加上从顶层到deep层的最小表面积如果都大于了已经得到的best,那么1到deep层是无论半径和高度取何值都是无效的
sumv + minv[deep] > n同理2 * (n - sumv) / r + sums >= best 这是该题的精髓,如果没有的话会造成超时,是为了把sumv和sums联系起来,原因如下:假设能够得到best时(为什么这样假设呢,因为如果得不到的话那么就已经被第一个剪枝滤去了,所以在第三个剪枝验证时表示已经通过了第一个剪枝的要求),n - sumv = h[1] * r[1] * r[1] + ... + h[deep] * r[deep] * r[deep] < h[1] * r[1] * r + ... + h[deep] * r[deep] * r (因为r是deep + 1层的半径)其中h[1]...h[deep]表示在函数的形参情况下,1到deep层应该取得h值,r[1]同理两边同时处以r 再乘以2得 2 * (n - sumv) / r < 2 * (h[1] * r[1] + ... + h[deep] * r[deep]) 2 * (n - sumv) / r < best - sums2 * (n - sumv) / r + sums < best 成立 ,则可得剪枝条件

AC代码:
#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAX 1002
#define pi 3
using namespace std;
int n,m,best=99999999;//无穷大定义为99999999 
int mins[21],minv[21];
void init()
{
for(int i=1;i<21;i++)
{
mins[i]=mins[i-1]+2*i*i;
minv[i]=minv[i-1]+i*i*i;
}

}
//从最底层开始向上进行搜索,最底层的蛋糕为第m层 
void dfs(int deep, int r, int h, int sumv, int sums) //sumv(sums)为从m层到c+1的蛋糕的体积(表面积) 
{
if(deep==0)
{
if(best>sums && sumv==n)//加上sunv==m是因为,当走到deep=0的时候,所得到的sumv不一定是n,只会比n小 
best=sums;
return;
}
if(sums+mins[deep]>best || sumv+minv[deep]>n || 2*(n-sumv)/r>=best-sums)
return;
for(int i=r-1;i>=deep;i--)//i>=deep,而不是i>=1,因为每一层的半径和高度最小为该层的层数 ,因为下面一层永远比上一层大,且题目
{                                      // 中Q外,都为正整数 
int maxh=min(h-1,(n-sumv-minv[deep-1])/(i*i));//n-sumv-minv[deep-1]表示第deep层的蛋糕的最大体积,除以i*i(底面积),等于
for(int j=maxh;j>=deep;j--)                                  //高
{
if(deep==m)//该蛋糕的表面积实际上是每一层蛋糕的侧面积加上最下面一层蛋糕底面积(或者说是上底面积),因为是
sums=i*i; //一层一层叠着的,且每一层的底面积都比上一层大,所以才能得到这个结论 
dfs(deep-1,i,j,sumv+i*i*j,sums+2*i*j);//继续向上搜索 
}
}
}


int main()
{
scanf("%d%d",&n,&m);
init(); 
dfs(m,sqrt(n)+1,n+1,0,0);//sqrt(n)是该蛋糕的最大半径,加1是它的上限,n+1同理得到,由V=pi*r*r*h(当r取1时,h最大,当h取1时r
if(best==99999999)         //最大) 
printf("0\n");
else printf("%d\n",best);
return 0;
}
0 0
原创粉丝点击