poj 1190 生日蛋糕(剪枝+深搜)

题目地址

题目大意:Nπ体积m层的蛋糕,使得表面积最小

解题思路:将蛋糕从上到下编号1...m,从m层开始搜索,搜索过程中注意剪枝

三个剪枝条件:
1、已经搜索过的体积加上还未搜索过的最小体积不能比总体积n 大
2、已经搜索过的表面积加上还未搜索过的最小表面积不能比之前的最小总表面积best 大
3、n-sumv既所剩体积记作dv 还需要的表面积为s
s=2*ri*hi+2*r(i-1)*h(i-1)+... >=2*ri*hi*ri/r+2*r(i-1)*h(i-1)*r(i-1)/r+...

  =2*dv/r(i从depth-1取,r为当前半径 ri/r<1)所以得到还需要的最小表面积s=2*(n-sumv)/r,如果最小的s和已经搜索过的表面积sums依然比best大 就不用继续搜索了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>

using namespace std;

const int inf=0xfffffff;

int n,m,minv[21],mins[21]; //minv[i]为从小到大的第i层的最小体积,最小表面积,从小到大(1...m)
int best=inf;				//best 最小表面积

void DFS(int depth,int sumv,int sums,int r,int h) //深度优先搜索 自底m向上搜索 r h表示当前层得半径和高度
												  //sumv已经用的总体积 sums已经生成的总表面积
{
	if(depth==0)
	{
		if(sumv==n&&sums<best)           //搜索完成,更新最小表面积best
		{
			best=sums;
		}
		return;
	}
	if(sumv+minv[depth-1]>n||sums+mins[depth-1]>best||sums+2*(n-sumv)/r>=best)  //剪枝如上所述
		return;
	for(int i=r-1;i>=depth;i--)    //递减顺序枚举depth层半径的每一个可能值,这里第depth层的半径最小值为depth
	{
		if(depth==m)
			sums=i*i;      //俯视蛋糕底面积作为外表面积的初始值(总的上表面积,以后只需计算侧面积)
		int maxh=min((n-sumv-minv[depth-1])/(i*i),h-1);
		                 //maxh最大高度,即depth层蛋糕高度的上限,(n-sumv-minv[dep-1])表示第depth层最大的体积
		for(int j=maxh;j>=depth;j--)    //同理,第depth层的最小高度值为depth
		{
			DFS(depth-1,sumv+i*i*j,sums+2*i*j,i,j);  //递归搜索子状态
		}
	}
}

int main()
{
	while(scanf("%d%d",&n,&m) != EOF)
    {
        int rmax=(int)sqrt((double)n); //rmax初始半径 底层半径 最大值为sqrt(n)
        int hmax=n;                    //hmax初始高度 高度最大为 n
        minv[0]=mins[0]=0;
        for(int i=1;i<=m;i++)
        {                              //初始化minv和mins数组
            minv[i]=minv[i-1]+i*i*i;   //从顶层(即第1层)到第i层的最小体积minv[i]成立时第j层的半径和高度都为j
            mins[i]=mins[i-1]+2*i*i;
        }
        DFS(m,0,0,rmax,hmax);
        if(best==inf)
            best=0;        //无解
        printf("%d\n",best);
    }
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值