POJ1190 生日蛋糕 DFS剪枝——C++详解

生日蛋糕

Time Limit: 1SMemory Limit: 10000K
Total Submissions: 28941Accepted: 10342

Description

制作一个体积为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

代码如下:

#include<iostream>
#include<cmath>
using namespace std;

int N,M;
int minArea=1<<30;	//最优表面积 
int area;		//正在搭建中的蛋糕的表面积
int mins[21],minv[21];

void dfs(int v,int n,int r,int h){
	//要用n层去凑体积v,最底层半径不能超过r,高度不能超过h
	//求出最小表面积放入minArea 
	if(n==0){
		if(v) return;
		else{
			minArea=min(minArea,area);
			return;
		}
	}
	
	if(v<=0)
		return;
		
	if(r<n||h<n)
	//可行性剪枝 
	//搭建过程中发现高度或者半径已经无法安排 
		return;
	
	if(minv[n]>v)
	//可行性剪枝 
	//搭建过程中发现还没搭的那些层的体积,一定会超过还缺的体积 
		return;
		
	if(area>=minArea||area+mins[n]>=minArea)	
	//最优性剪枝 
	//搭建过程中发现已建好的面积已经超过目前求得的最优表面积或者预见搭完后面积一定会超过目前最优表面积 
		return;
	
	int maxv=0,_r=r,_h=h;
	for(int i=n;i>=1;--i){
		maxv+=_r*_r*_h;
		--_r;
		--_h;
	}
	if(v>maxv)
	//可行性剪枝 
	//搭建过程中发现还没搭的那些层的体积,最大也达不到还缺的体积 
		return;
	
	for(int rr=r;rr>=n;--rr){
		if(n==M)
			area=rr*rr;
		for(int hh=h;hh>=n;--hh){
			area+=2*rr*hh;
			dfs(v-rr*rr*hh,n-1,rr-1,hh-1);
			area-=2*rr*hh;
		} 
	}
}

int main(){
	cin>>N>>M;
	//体积为N,层数为M
	
	int min_s,min_v;
	for(int i=0;i<=M;++i){
		min_s+=2*i*i;
		min_v+=i*i*i;
		mins[i]=min_s;
		minv[i]=min_v;
	}
	
	int maxR=sqrt(N-minv[M-1]);
	int maxH=N-minv[M-1]/M;
	dfs(N,M,maxR,maxH);
	
	if(minArea==1<<30)
		cout<<0<<endl;
	else
		cout<<minArea<<endl;
	
	return 0;
}

运行结果:

在这里插入图片描述

提醒:

代码已经对深搜进行了剪枝,但是还是超时,希望有能力的同学可以指点一下,感谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枯木何日可逢春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值