icpc:problems:生日蛋糕
problems | |
---|---|
名称 | 生日蛋糕 |
题目编号 | 168 |
题目链接 | acwing.com/… |
来源 | Acwing |
算法分类 | 搜索, DFS, 剪枝, 剪枝_例题 |
难易程度 | 一般般 |
生日蛋糕
想法
规定第1层为最低层,则由于每一层都需要比上一层要大,故第1层的$r$与$h$最小值均为$m$,可以得出第$x$层的$r$与$h$的最小值均为$m - x + 1$。
此题最重要的剪枝为对未来的最优性剪枝:假设当前枚举第x层的蛋糕,我们可以得出后$x \to m$层的体积为 $n - v = \sum^{m}_{i=x} h_i * r_i^2 $,表面积为 $2 * \sum^{m}_{i=x} h_i * r_i$。
假设当前第x层蛋糕的半径为$r_x$,由题意可知,后续的$r_i$均比$r_x$小。对后续的表面积公式进行放缩可得:
$$ 2 * \sum^{m}_{i=x} h_i * r_i = \frac{2}{r_x} * \sum^{m}_{i=x} h_i * r_i * r_x \geq \frac{2}{r_x} * \sum^{m}_{i=x} h_i * r_i * r_i = \frac{2 * (n - v)}{r_x}$$
所以我们可以预估出后续最小的表面积为 $\frac{2 * (n - v)}{r_x}$,当 $s + \frac{2 * (n - v)}{r_x} > ans$时,说明当前搜索的情况不是最优的,需要对其进行剪枝。
代码实现
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; int n, m, ans = 0x7f7f7f7f; void DFS(int x, int s = 0, int v = 0, int front_r = sqrt(n), int front_h = n) { if(x > m) { if(v == n) ans = ans > s ? s : ans; return ; } for (int r = min((int)floor(sqrt(n-v)), front_r-1); r >= m-x+1; r--){ if(2*(n-v)/r + s > ans) break; for (int h = min((int)floor(1.0*(n-v)/(r*r)), front_h-1); h >= m-x+1; h--) { DFS(x + 1, s + 2 * r * h + (x == 1 ? r * r : 0), v + r * r * h, r, h); } } return ; } int main() { scanf("%d %d", &n, &m); DFS(1); printf("%d", ans == 0x7f7f7f7f ? 0 : ans); return 0; }
/app/www/public/data/pages/icpc/problems/生日蛋糕.txt · 最后更改: 2023/07/09 03:51 由 温婕莺