NOI题库192 生日蛋糕

时间:2023-03-22 10:11:56

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 = +;
const int INF=1e9; int minv[maxn],mins[maxn];
int n,m,ans; void init() {
for(int i=;i<=m;i++) {
minv[i]=minv[i-]+i*i*i;
mins[i]=mins[i-]+*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 ||( * (n - v) / r + S >= ans) ) return ; for(int nowr=r-;nowr>=dep;nowr--) {
if(dep==m) S=nowr*nowr;
int maxh=min(h-,n-v-minv[dep-]/nowr*nowr);
for(int nowh=maxh;nowh>=dep;nowh--)
{
dfs(dep-,v+nowr*nowr*nowh,nowr,nowh,S+*nowr*nowh);
}
}
} int main() {
cin>>n>>m;
init();
ans=INF;
dfs(m,,sqrt(n),n+,); //当只有一层时得到 R H 上限
if(ans==INF) cout<<;
else cout<<ans;
return ;
}