您的位置:首页 > 其它

NOI题库192 生日蛋糕

2015-11-04 15:14 330 查看
192:生日蛋糕

总时间限制:

5000ms

内存限制:

65536kB

描述

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 <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。

输出

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

样例输入

100

2

样例输出

68

提示

圆柱公式

体积V = πR2H

侧面积A' = 2πRH

底面积A = πR2

来源

Noi 99

【思路】

搜索+剪枝。

依次搜索每一层的高度与半径。三个剪枝策略如下:

//这里用到的三个剪枝
//sums + mins[deep]> best 表示以前的到的deep + 1层到 m 层的表面积加上从顶层到deep层的最小表面积如果都大于了已经得到的best,那么1到deep层是无论半径和高度取何值都是无效的
//sumv + minv[deep] > n同理
// 2 * (n - sumv) / r + sums >= best 这是该题的精髓,如果没有的话会造成超时,是为了把sumv和sums联系起来,原因如下:
// 假设能够得到best时(为什么这样假设呢,因为如果得不到的话那么就已经被第一个剪枝滤去了,所以在第三个剪枝验证时表示已经通过了第一个剪枝的要求),
// n - sumv = h[1] * r[1] * r[1] + ... + h[deep] * r[deep] * r[deep] < h[1] * r[1] * r + ... + h[deep] * r[deep] * r (因为r是deep + 1层的半径)
//其中h[1]...h[deep]表示在函数的形参情况下,1到deep层应该取得h值,r[1]同理
// 两边同时处以r 再乘以2得 2 * (n - sumv) / r < 2 * (h[1] * r[1] + ... + h[deep] * r[deep])
// 2 * (n - sumv) / r < best - sums
// 2 * (n - sumv) / r + sums < best 成立 ,则可得剪枝条件


【代码】

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

using namespace std;

const int maxn = 20+5;
const int INF=1e9;

int minv[maxn],mins[maxn];
int n,m,ans;

void init() {
for(int i=1;i<=m;i++) {
minv[i]=minv[i-1]+i*i*i;
mins[i]=mins[i-1]+2*i*i;
}
}

void dfs(int dep,int v,int r,int h,int S) {
if(!dep) {
if(v==n&&S<ans) ans=S;
return ;
}
if(S+mins[dep]>ans || v+minv[dep]>n ||(2 * (n - v) / r + S >= ans) ) return ;

for(int nowr=r-1;nowr>=dep;nowr--) {
if(dep==m) S=nowr*nowr;
int maxh=min(h-1,n-v-minv[dep-1]/nowr*nowr);
for(int nowh=maxh;nowh>=dep;nowh--)
{
dfs(dep-1,v+nowr*nowr*nowh,nowr,nowh,S+2*nowr*nowh);
}
}
}

int main() {
cin>>n>>m;
init();
ans=INF;
dfs(m,0,sqrt(n),n+1,0);  //当只有一层时得到 R H 上限
if(ans==INF) cout<<0;
else cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: