【poj1190】生日蛋糕 搜索剪枝 公式推导最小面积

生日蛋糕

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 25000 Accepted: 8945

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 

代码主体部分并不是我的,我只是站在巨人的肩膀上加了一些自己的理解

以帮助大家更好地学习

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXM = 23;
const int MAXN = 1e4+10;
int lminQ[MAXM], lminV[MAXM];
int min_Q;
int N, M;

///已经凑的体积,已经凑的表面积,当前在第几层,下一层的半径,下一层的高
void dfs(int V, int Q, int step, int r, int h)
{
    if(step == 0)          ///层数用完
    {
        if(V == N) min_Q = min(min_Q, Q);  ///体积刚刚好
        return;
    }
    if(V+lminV[step] > N||Q+lminQ[step] >= min_Q) return;    //剪枝:如果当前体积加上理论最小体积超过N或者当前表面积加理论最小表面积超过最优值
    /*
        原句是if(V+lminV[step] > N || Q+lminQ[step] >= min_Q),但是会发现后半句的范围比下面的少
        因为lmin只是规定了高为1时候的最小值,换句话说,当符合Q+lminQ[step] >= min_Q的条件会更少一些
        所以下一句if(2*(N-V)/r + Q >= min_Q) return的优化程度很大,因为它考虑了当前的实际情况
        当然加上以后更快一些
    */
    if(2*(N-V)/r + Q >= min_Q) return;                  //剪枝:假设最小的表面积已经大于等于最优值,则没有继续搜的意义了
    ///其中Q是最底层的面积,因为俯视来看,上面都是需要刷的,而那些面积等同于底面积
    int max_R = r-1;             ///最大半径为上一层半径减一
    for(int i = max_R; i >= step; i--)  ///枚举半径
    {
        if(step == M)        ///当前在最底层
        {
            Q = i*i;         ///表面积加上最底层的底面积
        }
        int max_H = h-1;         ///最大的高度
        for(int j = max_H; j >= step; j--)
        {
            dfs(V+i*i*j, Q+2*i*j, step-1, i, j);
        }
    }
}
int main()
{
    scanf("%d%d", &N, &M);
    lminQ[0] = 0, lminV[0] = 0;
    for(int i = 1; i < 22; i++)       ///预处理每一层的理论最小值
    {
        lminQ[i] = lminQ[i-1] + 2*i*i;
        lminV[i] = lminV[i-1] + i*i*i;
    }
    min_Q = INF;
    dfs(0, 0, M, 100, 10000);///体积最大是10000,所以高最高10000,半径最大100
    if(min_Q < INF) printf("%d\n", min_Q);
    else printf("0\n");
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值