Description:
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第
i
(
1
≤
i
≤
M
)
i(1\leq i \leq M)
i(1≤i≤M)层蛋糕是半径为 Ri , 高度为 Hi 的圆柱。当
i
<
M
i < M
i<M 时,要求
R
i
>
R
i
+
1
R~i~ > R~i+1~
R i >R i+1 且
H
i
>
H
i
+
1
H~i~ > H~i+1~
H i >H i+1 。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。(除Q外,以上所有数据皆为正整数)
解题思路:
算法标签:DFS
采用自底向上的搜索。由题可知,所有数均为正整数,所以所有计算无需关心
π
\pi
π 。
首先确定半径R的最大值,高度H的最大值。
当高度均为1时,R最大。
当圆柱上表面面积均为1时,H最大。
因为所有数据均为正整数,所以可以求得第 i 层到第 1 层的最小体积和最小侧面积,假设第一层半径R为1。
即
:
:
:
m
i
n
v
[
i
]
=
m
i
n
v
[
i
−
1
]
+
i
∗
i
∗
i
minv[i] = minv[i-1] + i*i*i
minv[i]=minv[i−1]+i∗i∗i
(
1
≤
i
≤
m
)
(1 \leq i \leq m)
(1≤i≤m)
m
i
n
s
[
i
]
=
m
i
n
s
[
i
−
1
]
+
2
∗
i
∗
i
mins[i] = mins[i-1] + 2*i*i
mins[i]=mins[i−1]+2∗i∗i
(
1
≤
i
≤
m
)
(1 \leq i \leq m)
(1≤i≤m)
DFS种三个剪枝条件:
- 当第 depth 层时,当前体积 sumv 加上最小体积minv[depth-1] 大于 n时,显然无需继续搜索。
- 当第 depth 层时,当前侧面积 sumv 加上最小侧面积mins[depth-1]大于目前已经得到的结果,显然无需继续搜索。
- 设剩余面积
d
v
=
n
−
s
u
m
v
dv = n - sumv
dv=n−sumv ,
还需要的表面积 :
s = 2 × \times ×ri × \times ×hi + 2 × \times ×ri-1 × \times ×hi-1 + ⋯ \cdots ⋯ +2 × \times ×r1 × \times ×h1 ≥ \geq ≥ 2 × \times ×ri × \times ×hi × \times ×(ri/r) + 2 × \times ×ri-1 × \times ×hi-1 × \times ×(ri-1/r) + ⋯ \cdots ⋯ +2 × \times ×r1 × \times ×h1 × \times ×(r1/r) = 2*dv/r
( 1 ≤ i ≤ d e p t h − 1 ) (1 \leq i \leq depth-1) (1≤i≤depth−1)
r 为当前半径,可知 r > > > ri ,即 (ri / r) < 1
如果当前侧面积sums 加上最小面积 s 大于已经得到的结果,显然就没有必要继续搜索。
搜索过程中,上一次的半径 R 和高度 H 一定比下一层的小,所以遍历时候此为循环条件
代码:
// TSWorld
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
// 初始化
const long long N = 30;
const int MAXX = 0x3f3f3f3f;
// 定义
int n,m;
// 最小体积和最小面积
int minv[N],mins[N];
// result
int ans;
void DFS(int depth,int sumv,int sums,int r,int h) {
if(depth == 0) {
if(sumv == n && sums < ans)
ans = sums;
return;
}
if(sumv + minv[depth-1] > n)
return;
if(sums + mins[depth-1] > ans)
return;
if(sums+2*(n-sumv)/r >= ans)
return;
// 因为R值最小为1,所以每一层最小值等于其所在层数
for(int i = r-1;i >= depth;i--) {
// 俯视蛋糕的面积,即为最底层的上表面积
if(depth == m)
sums = i*i;
// 体积最大时候的最大高度
int H_best = min(h-1,(n-sumv-minv[depth-1])/(i*i));
for(int j = H_best;j >= depth;j--)
DFS(depth-1,sumv+i*i*j,sums+2*i*j,i,j);
}
}
int main()
{
int R_best = 0,H_best = 0;
// input
cin>>n>>m;
// the best of R when H is 1
R_best = sqrt(double(n));
// the best of H when area is 1
H_best = n;
// 计算第一层到第i层的最小体积和面积,每次递增为1
for(int i = 1;i <= m;i++) {
mins[i] = mins[i-1] + 2*i*i;
minv[i] = minv[i-1] + i*i*i;
}
// 因为求最小值,ans初始化为最大值
ans = MAXX;
DFS(m,0,0,R_best,H_best);
if(ans == MAXX)
cout<<0;
else
cout<<ans;
return 0;
}