生日蛋糕 (poj1190) (dfs剪枝)

【题目描述】
    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外,以上所有数据皆为正整数)
【题目链接】

生日蛋糕

【算法】

dfs剪枝。
1)搜索顺序:自下往上,自大往小。(自小往大就玄学的T和R了qwq)
2)上下界剪枝:R和H的枚举控制范围
3)可行性剪枝a:当前体积加上未计算层的最小体积超过n,剪枝
4)可行性剪枝b:当前体积加上未计算层的最大体积小于n,剪枝
4)最优性剪枝:当前表面积加上最小表面积超过ans,剪枝
5)高级最优性剪枝:数学公式推导一波
改掉头文件后,loj14ms。。。。(还可以输入优化,不过感觉没必要)

【代码】
#include <bits/stdc++.h>
using namespace std;
int n,m,ans=1e9;
int recv[25],recs[25],h[25],r[25];
int cal(int h,int r,int dep) {
    if(!dep) return 0;
    return r*r*h+cal(h-1,r-1,dep-1);
}
void dfs(int dep,int s,int v) {
    if(dep==0) {
        if(v==n) ans=min(ans,s);
        return;
    }
    for(int R=min(r[dep+1]-1,(int)(sqrt(n-v)));R>=dep;R--) {
        for(int H=min(h[dep+1]-1,(n-v)/(R*R));H>=dep;H--) {
            int curv=R*R*H,curs=2*R*H;
            if(v+curv+recv[dep-1]>n) continue;
            if(s+curs+recs[dep-1]>=ans) continue;
            if(s+curs+2*(n-v-curv)/R>=ans) continue;
            if(v+curv+cal(H-1,R-1,dep-1)<n) break;
            h[dep]=H,r[dep]=R;
            if(dep==m) s=R*R;
            dfs(dep-1,s+curs,v+curv);
            if(dep==m) s=0;
        }
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) recv[i]=i*i*i+recv[i-1],recs[i]=2*i*i+recs[i-1];
    h[m+1]=r[m+1]=1e9;
    dfs(m,0,0);
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/Willendless/p/9532301.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值