生日蛋糕 POJ - 1190 (搜索+剪枝)

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

100
2

Sample Output

68

Hint

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

 
思路:正常深搜,但是会TLE,需要众多剪枝
①我们可以预处理1~当前层所需的最小表面积和体积,然后如果已经选的表面积(体积)+ 剩下最小表面积(体积)超过ans(N规定体积)就return
②枚举r,h时,我们可以知道规定枚举范围,就不需要每次减一递减
maxR = min(r,sqrt(N-SumV-minV[now-1])
maxH = min(h,(n-SumV-minV[now-1])/(i*i))
③最难的一个剪枝:
n-SumV = Σh【k】*r【k】*r【k】   (1<=k<=now)               
2*Σr【k】*h【k】= 2/r【now+1】*Σr【k】*h【k】*r【now+1】 >=  2/r【now+1】*Σh【k】*r【k】*r【k】(1<=k<=now)
2*Σr【k】*h【k】 >= 2*(n-SumV)/r【now+1】  (1 <= k <= n)
所以 SumS + = 2*(n-SumV)/r【now+1】 >= ans 就return
 
#include<cstdio>
#include<cstdio>
#include<algorithm>
#include<math.h>
using namespace std;

int n,m,ans;
int minV[22];
int minS[22];
void dfs(int now,int SumS,int SumV,int r,int h,int last)
{
    if(SumS + minS[now] > ans)
        return;
    if(SumV + minV[now] > n)
        return;
    if(SumS + 2*(n-SumV)/last >= ans)
        return;
    if(!now)
    {
        if(SumV == n && SumS < ans)
            ans = SumS;
        return;
    }
    int maxR = min(r,(int)sqrt(n-SumV-minV[now-1]));
    for(int i=maxR;i>=now;i--)
    {
        if(now == m)SumS = i*i;
        int maxH = min((n-minV[now-1]-SumV)/(i*i), h);
        for(int j=maxH;j>=now;j--)
        {
            dfs(now-1,SumS+2*i*j,SumV+i*i*j,i-1,j-1,r);
        }
    }
}

int main()
{
    ans = 0x3f3f3f3f;
    for(int i=1; i<=18; i++)
    {
        minV[i] += minV[i-1] + i*i*i;
        minS[i] += minS[i-1] + 2*i*i;
    }
    scanf("%d%d",&n,&m);
    dfs(m,0,0,100,10000,200);
    if(ans == 0x3f3f3f3f)ans = 0;
    printf("%d\n",ans);
}
View Code
 
 
 

猜你喜欢

转载自www.cnblogs.com/iwannabe/p/10581693.html
今日推荐