POJ-1190-生日蛋糕(深搜,剪枝)

生日蛋糕

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 23049 Accepted: 8215

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

100
2

Sample Output

68

Hint

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

分析

  • 由于要计算表面积(露出来的),那么在一层一层的计算过程中,如果最下面的一层确定了,则上表面积就确定了,所以搜索框架从下到上。
  • 搜索面对的状态有:正在搜索蛋糕第dep层,当前的外表面积,当前的体积,第dep+1层的高度和半径。
  • 在第dep层时,要枚举所有符合要求的高度和半径
    • 半径:$R\in[dep,min(\lfloor\sqrt{N-v}\rfloor,r[dep+1]-1)]$
    • 高度:$H\in[dep,min(\lfloor (N-v)/R^2\rfloor,h[dep+1]-1)]$
    • 上面两个右边界的式子可以通过圆柱体积公式 $\pi R^2H =\pi(N-v)$
  • 在上面确定的范围中,使用倒序枚举。R越大,表面积越小
  • 可行性剪枝
    • 可以预处理出从上往下前 $i(1\leq i\leq M)$ 层最小体积和侧面积.显然,当第 1~i 层的半径分别取 1,2,3,... ,i,高度也分别取 1,2,3,... ,i,时,有最小体积与侧面积。
    • 如果当前体积加上1~dep-1 层的最小体积大于N,可以剪枝。
  • 最优性剪枝一,如果当前表面积s加上 1~dep-1 层的最小侧面积大于已经搜到的答案,或者当前体积加上1~dep-1 层的最大体积小于 v,剪枝
  • 最优性剪枝二,通过转换可以得到 $\frac{2(n-v)}{r[dep]} + s$ 大于已经搜到的答案时,可以剪枝。
#define MAX 19931117
int minv[30];
int mins = MAX;
int v,m;
int maxcake (int n, int lr, int lh)
{
    int ans = 0, i;
    for (i = n, lr--, lh--; i <= m; i++, lr--, lh--)
    {
        ans += lr * lr * lh;
        if (ans >= 10000 || lr * lr * lh >= 10000) return 10000;
    }
    return ans;
}

void dfs(int n,int lr,int lh,int uv,int us)
{
    if(us>=mins)return;
    if(uv+minv[m-n+1]>v|| uv + maxcake(n, lr, lh) < v)return;
    int r,h;
    if(n==m)
    {
        for(r = lr-1;r>=1;r--)
        {
            if((v-uv)%(r*r))continue;
            h=(v-uv)/(r*r);
            if(h>=lh)continue;
            mins = min(mins,us+2*r*h+(m==1?(r*r):0));
        }
        return;
    }
    else
    {
        for(r = lr-1;r>=m-n+1;r--)
        {
            for(h=min(lh - 1, (int)((v - uv) / (r * r))); h >= m - n + 1; h--)
            {
                if (n == 1) dfs(2, r, h, r * r * h, r * r + 2 * r * h);
                else dfs(n + 1, r, h, uv + r * r * h, us + 2 * r * h);
            }
        }
        return ;
    }
}
int main()
{
    cin>>v>>m;
    minv[0] = 0;
    for(int i = 1;i<=m;i++)
        minv[i] = minv[i-1]+i*i*i; 
    dfs(1,101,10001,0,0);
    if(mins==MAX)
        cout<<0<<endl;
    else
        cout<<mins<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1625--H/p/9497827.html