「NOI1999」「LuoguP1731」生日蛋糕(爆搜剪枝

题目背景

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外,以上所有数据皆为正整数)

题目描述

输入输出格式

输入格式:

有两行,第一行为N(N<=20000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=15),表示蛋糕的层数为M。

输出格式:

仅一行,是一个正整数S(若无解则S=0)。

输入输出样例

输入样例#1: 复制
100
2
输出样例#1: 复制
68

题解

可以说是童年阴影了。

众所周知的一道爆搜题,考点大概是剪枝?

 1 /*
 2     qwerta
 3     P1731 [NOI1999]生日蛋糕
 4     Accepted
 5     100
 6     代码 C++,1.45KB
 7     提交时间 2018-10-10 11:55:48
 8     耗时/内存
 9     760ms, 1256KB
10 */
11 #include<iostream>
12 #include<cstdio>
13 #include<cmath>
14 using namespace std;
15 #define R register
16 int n,m;
17 long long q=999999999999999;
18 int f[16][103][10003];
19 int fx[21][2];
20 void search(int d,int rbef,int hbef,int vres,int sbef)//d:深度 rbef:上一层半径 hbef:上一层高度 vres:还剩的体积 sbef:已经用了多少面积
21 {
22     if(d==m+1)
23     {
24         if(vres==0)
25           q=min(q,(long long)sbef);//搜到了就更新
26           return;
27     }
28     if(vres<=0)return;//没体积了,剪掉
29     if(sbef>q)return;//面积大了,剪掉
30     if(rbef<=(m-d+1))return;//半径小了不够搭这么多层,剪掉
31     if(hbef<=(m-d+1))return;//高度矮了不够搭这么多层,剪掉
32     if(2*vres/rbef+sbef>q)return;//划重点!如果当前体积的最小面积还大了,剪掉
33     //
34     if(fx[d][0])//记忆化 fx[d][0]记录还剩d层时至少要的体积,fx[d][1]为面积
35     {         
36         if(fx[d][0]>vres)return;//剩体积的不够用,剪掉
37         if(fx[d][1]+sbef>q)return;//最小的法子涂也面积大了,剪掉
38     }
39     else 
40     {
41         int v=0,s=0;
42         for(R int i=d;i<=m;++i)//for一遍
43         {
44             int r=(m+1-i);
45             int h=(m+1-i);
46             v+=r*r*h,s+=2*r*h;
47         }
48         fx[d][0]=v;
49         fx[d][1]=s;
50         if(v>vres)return;
51         if(s+sbef>q)return;
52     }
53     //
54     if(f[d][rbef][hbef])//记录在d,rbef,hbef的情况下的最大体积
55     {
56         if(f[d][rbef][hbef]<vres)return;//往大了搭还小了,剪掉
57     }
58     else
59     {
60         int v=0;
61         for(R int i=d;i<=m;++i)
62         {
63             int r=(rbef-(i-(d-1)));
64             int h=(hbef-(i-(d-1)));
65             v+=r*r*h;
66         }
67         f[d][rbef][hbef]=v;
68         if(v<vres)return;
69     }
70     //剪爽了,开始搜
71     for(R int r=1;r<rbef;++r)
72     for(R int h=1;h<hbef;++h)
73     {
74         int s=0;
75         if(d==1)s=r*r;
76         search(d+1,r,h,vres-r*r*h,sbef+s+2*r*h);
77     }
78     return;
79 }
80 int main()
81 {
82     //freopen("a.in","r",stdin);
83     scanf("%d%d",&n,&m);
84     search(1,101,10001,n,0);
85     cout<<q;
86     return 0;
87 }
代码又慢又长哦,真的要看吗QAQ

 

转载于:https://www.cnblogs.com/qwerta/p/9769563.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值