POJ 1190 生日蛋糕(dfs + 剪枝)

传送门

中文题目而且这么短小的题干相信大家都看的很明白(笑着哭),我就不说了。题目对每一层的半径和高度都有限制,下层的半径和厚度要大于上层的半径和厚度 Ri > Ri-1, Hi > Hi-1,且半径和厚度均为整数。这样的话肯定是用搜索没错了,但是还有一些情况根本不会得到解,我们就没必要再浪费时间走下去了,这样就需要剪枝。具体情况具体分析,代码如下

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
int v,M,mins;
int leftmins[21],leftminv[21];
///leftmins[i]表示第i层及其之上各层的最小表面积,另一个表示最小体积
void dfs(int v,int m,int lastr,int lasth,int sums)
{
    /*v:剩余体积
    m:剩余层数
    lastr:下一层半径
    lasth:下一层高度
    sums:已经搭好的表面积的和*/
    if(m == 0 && v == 0)
    {
        if(sums < mins)
            mins = sums;
        return;
    }
    if(leftmins[m] + sums >= mins)
        return;
    if(leftminv[m] > v)
        return;
    ///剪枝
    int avgv = v / m;
    for(int r = lastr - 1;r >= m; r--)
    {
        for(int h = lasth - 1;h >= m; h--)
        {
            int curv = r * r * h;
            if(curv < avgv)
                break;
            if(curv > v)
                continue;
            int leftmaxv = 0;
            for(int i = 1;i < m; i++)
                leftmaxv += (r - i) * (r - i) * (h - i);
            if(v - curv > leftmaxv)
                break;
            if(m  == M)
                sums = r * r;
            dfs(v - curv,m - 1,r,h,sums + 2 * r * h);
        }
    }
}
int main()
{
    for(int i = 1;i <= 20; i++)
        for(int j = 0;j < i; j++)
        {
            leftmins[i] = (i - j) * (i - j);
            leftminv[i] = (i - j) * (i - j) * (i - j);
        }
    scanf("%d %d",&v,&M);
    mins = inf;
    dfs(v,M,sqrt(1.0 * v) + 1,v + 1,0);
    int ans = mins < inf ? mins : 0;
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiao__hei__hei/article/details/87860649
今日推荐