POJ1190 生日蛋糕(DFS剪枝)

Description:

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第 i ( 1 ≤ i ≤ M ) i(1\leq i \leq M) i(1iM)层蛋糕是半径为 Ri , 高度为 Hi 的圆柱。当 i < M i < M i<M 时,要求 R   i   > R   i + 1   R~i~ > R~i+1~ R i >R i+1  H   i   > H   i + 1   H~i~ > H~i+1~ H i >H i+1 
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。(除Q外,以上所有数据皆为正整数)

解题思路:

算法标签:DFS
采用自底向上的搜索。由题可知,所有数均为正整数,所以所有计算无需关心 π \pi π
首先确定半径R的最大值,高度H的最大值。
当高度均为1时,R最大。
当圆柱上表面面积均为1时,H最大。
因为所有数据均为正整数,所以可以求得第 i 层到第 1 层的最小体积和最小侧面积,假设第一层半径R为1。
: : :
m i n v [ i ] = m i n v [ i − 1 ] + i ∗ i ∗ i minv[i] = minv[i-1] + i*i*i minv[i]=minv[i1]+iii ( 1 ≤ i ≤ m ) (1 \leq i \leq m) (1im)
m i n s [ i ] = m i n s [ i − 1 ] + 2 ∗ i ∗ i mins[i] = mins[i-1] + 2*i*i mins[i]=mins[i1]+2ii ( 1 ≤ i ≤ m ) (1 \leq i \leq m) (1im)
DFS种三个剪枝条件:

  1. 当第 depth 层时,当前体积 sumv 加上最小体积minv[depth-1] 大于 n时,显然无需继续搜索。
  2. 当第 depth 层时,当前侧面积 sumv 加上最小侧面积mins[depth-1]大于目前已经得到的结果,显然无需继续搜索。
  3. 设剩余面积 d v = n − s u m v dv = n - sumv dv=nsumv ,
    还需要的表面积 :
    s = 2 × \times ×ri × \times ×hi + 2 × \times ×ri-1 × \times ×hi-1 + ⋯ \cdots +2 × \times ×r1 × \times ×h1 ≥ \geq 2 × \times ×ri × \times ×hi × \times ×(ri/r) + 2 × \times ×ri-1 × \times ×hi-1 × \times ×(ri-1/r) + ⋯ \cdots +2 × \times ×r1 × \times ×h1 × \times ×(r1/r) = 2*dv/r
    ( 1 ≤ i ≤ d e p t h − 1 ) (1 \leq i \leq depth-1) (1idepth1)
    r 为当前半径,可知 r > > > ri ,即 (ri / r) < 1
    如果当前侧面积sums 加上最小面积 s 大于已经得到的结果,显然就没有必要继续搜索。


    搜索过程中,上一次的半径 R 和高度 H 一定比下一层的小,所以遍历时候此为循环条件

代码:

// TSWorld
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;

// 初始化
const long long N = 30;
const int MAXX = 0x3f3f3f3f;

// 定义
int n,m;
// 最小体积和最小面积
int minv[N],mins[N];
// result
int ans;

void DFS(int depth,int sumv,int sums,int r,int h) {

	if(depth == 0) {
		if(sumv == n && sums < ans)
			ans = sums;
		return;
	}

	if(sumv + minv[depth-1] > n)
		return;

	if(sums + mins[depth-1] > ans)
		return;

	if(sums+2*(n-sumv)/r >= ans)
		return;
	// 因为R值最小为1,所以每一层最小值等于其所在层数
	for(int i = r-1;i >= depth;i--) {
		// 俯视蛋糕的面积,即为最底层的上表面积
		if(depth == m)
			sums = i*i;
		// 体积最大时候的最大高度
		int H_best = min(h-1,(n-sumv-minv[depth-1])/(i*i));
		for(int j = H_best;j >= depth;j--) 
			DFS(depth-1,sumv+i*i*j,sums+2*i*j,i,j);
	}
}
int main()
{
	int R_best = 0,H_best = 0;
	
	// input
	cin>>n>>m;
	// the best of R when H is 1
	R_best = sqrt(double(n));
	// the best of H when area is 1
	H_best = n;

	// 计算第一层到第i层的最小体积和面积,每次递增为1
	for(int i = 1;i <= m;i++) {
		mins[i] = mins[i-1] + 2*i*i;
		minv[i] = minv[i-1] + i*i*i;
	}

	// 因为求最小值,ans初始化为最大值
	ans = MAXX;

	DFS(m,0,0,R_best,H_best);

	if(ans == MAXX)
		cout<<0;
	else
		cout<<ans;
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值