题目描述
7 7 7 月 17 17 17 日是 M r . W Mr.W Mr.W 的生日, A C M − T H U ACM-THU ACM−THU 为此要制作一个体积为 N N Nπ 的 M M M 层生日蛋糕,每层都是一个圆柱体。设从下往上数第 i ( 1 ≤ i ≤ M ) i(1 \leq i \leq M) i(1≤i≤M) 层蛋糕是半径为 R i R_i Ri , 高度为 H i H_i Hi 的圆柱。当 i < M i < M i<M_i<M i<Mi<M 时,要求 R i > R i + 1 R_i>R_i+1 Ri>Ri+1 且 H i > H i + 1 H_i>H_i+1 Hi>Hi+1 。由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积 Q Q Q 最小。
令 Q = S Q=S Q=Sπ ,请编程对给出的 N N N 和 M M M ,找出蛋糕的制作方案(适当的 R i R_i Ri 和 H i H_i Hi 的值),使 S S S 最小。
(除 Q Q Q 外,以上所有数据皆为正整数)
输入格式
有两行,第一行为 N ( N ≤ 10000 ) N \ (N \leq 10000) N (N≤10000) ,表示待制作的蛋糕的体积为 N N Nπ ;第二行为 M ( M ≤ 20 ) M \ (M \leq 20) M (M≤20),表示蛋糕的层数为 M M M。
输出格式
仅一行,是一个正整数 S S S(若无解则 S = 0 S=0 S=0 )。
输入样例
100
2
输出样例
68
样例说明
附:圆柱公式体积 V = π R 2 H V=πR^2H V=πR2H ,侧面积 A = 2 π R H A=2πRH A=2πRH ,底面积 A = π R 2 A=πR^2 A=πR2。
解题思路
DFS+剪枝
标准程序
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
//minv 和 mins 数组表示1~20层每层最小的体积和最小的侧面积
int n, m, minv[25], mins[25], ans = 1e9;
// v 当前体积 s 当前面积 dep 当前层次 r 最大半径 h 最大高度
void dfs(int v, int s, int dep, int r, int h) {
//递归出口
if (dep == 0) {
//制作到m层,且体积等于 n 取结果的最小值
if (v == n) ans = min(ans, s);
return;
}
//-----剪枝操作start--------//
//当前体积+最小体积都大于n,则方案不可行
if (v + minv[dep - 1] > n) return;
//当前面积+最小面积大于当前最优解 则该方案一定不是最优解
if (s + mins[dep - 1] > ans) return;
//当前面积+剩余的面积大于等于当前最优解,则该方案一定不是最优解
//注意包含等于,为何?因为剩余的最大面积是在半径相同的情况下,而题目要求半径是递减的
if (2 * (n - v) / r + s >= ans) return;
//-----剪枝操作end---------//
//枚举可能的半径,注意半径的最小值应该是当前层次
for (int i = r - 1; i >= dep; i--) {
//如果是最后一层直接+上表面面积,因为蛋糕是累加的,从上面看就是最后一层的面积。
//其他层其实只增加表面积
if (dep == m) s = i * i;
//获取高度的最大值,剩余体积/面积 ,当然还要确保满足大于等于h-1
int hh = min(h - 1, (n - v - minv[dep - 1]) / (i * i));
//枚举可能的高度
for (int j = hh; j >= dep; j--)
dfs(v + i * i * j, s + 2 * i * j, dep - 1, i, j); //dfs
}
}
int main() {
scanf("%d%d", &n, &m);
//预处理 20层每层最小体积和最小侧面积。
//因为上次层高度和半径差最小值是 1,所以直接枚举一下
for (int i = 1; i <= 20; i++) {
minv[i] = minv[i - 1] + i * i * i; // 前两个i表示半径 后一个i表示高度 计算体积
mins[i] = mins[i - 1] + 2 * i * i; // 第一个i表示半径 后一个i表示高度 计算侧面积
}
//sqrt(n) 对半径做了优化
dfs(0, 0, m, sqrt(n), n + 1); //dfs
if (ans >= 1e9)
printf("0\n");
else
printf("%d\n", ans);
return 0;
}