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外,以上所有数据皆为正整数)
设从下往上数第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 = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
体积V = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
题意:难得的中文题,给出蛋糕体积和层数,求出最小的表面积。
因为π都省略了,所以可以直接用正整数来计算。首先这是一道 深搜+剪枝的题目,面积可以用 r*r 来计算,体积可以用 r*r*h 来计算。
看了大神的博客才知道剪枝的条件,简直是神剪枝。
三个剪枝是:
1.总体积减去蛋糕当前层以下的层的总体积是否小于上面的层所能构成的最小体积。如果小于则返回。
2.已算得的答案(最小面积)减去蛋糕当前层以下的层的总面积是否小于上面的层所能构成的最小面积。如果小于则返回。
3.设剩余总体积为总体积减去蛋糕下面的层的总体积,剩余总面积是当前已得最优解减去蛋糕当前层以下的层的总面积。设ri为每层的半径,hi为每层的高度。蛋糕上面层的总面积是对2*ri*hi求和。总体积ri*ri*hi求和。剩余总体积*2再除以当前层的半径必须小于剩余总面积,否则返回。(2×sigma(ri*ri*hi)/rk > sigma(2*ri*hi) i=1~k)之所以左边大于右边是因为rk>ri 对于i<k。
#include <cstdio>
#include <cmath>
const int INF = 0x3f3f3f3f;
int ans;
int layer, tot_v;
int min_v[25], min_s[25];
void DFS(int s, int v, int n, int max_r, int max_h)
{
if (n == 0)
{
if (v != tot_v)
return;
ans = ans < s ? ans : s;
return;
}
if (tot_v - v < min_v[n])
return;
if (ans - s < min_s[n])
return;
if (n < layer && ans - s < 2 * (tot_v - v) / max_r)
return;
for (int i = max_r; i >= n; --i)
{
if (n == layer)
s = i*i;
int h = (tot_v - min_v[n-1] - v) / (i*i);///calculate the high
for (int j = h < max_h ? h : max_h; j >= n; --j)
DFS(s + 2*i*j, v + i*i*j, n - 1, i - 1, j - 1);
}
}
int main()
{
while (scanf("%d%d", &tot_v, &layer) != EOF)
{
ans = INF;
min_s[0] = 0;
min_v[0] = 0;
for (int i = 1; i < 25; ++i)
{
min_s[i] = min_s[i - 1] + 2 * i * i;
min_v[i] = min_v[i - 1] + i * i * i;
}
DFS(0, 0, layer, sqrt(tot_v), tot_v);
printf("%d\n", ans);
}
return 0;
}