【NOI1999】生日蛋糕
Description
制作一个m层,体积为n的蛋糕,每层都是一个圆柱体,且下面的圆柱体的半径和高度必须大于上面的,求一种方案使得表面积最小(表面积不含底面积)
Solution
搜索题,我们考虑如下优化(假定当前搜索到第i层,已经用了体积v,表面积s):
- 为了减少搜索分支的数量,我们从下往上搜索,且从大到小枚举半径和长度
- 确定半径和高度的上下界:$nowr\in\left[dep, min(r[dep+1]-1,\sqrt{n-v})\right]$,$nowh\in\left[dep, min(h[dep+1]-1,\frac{n-v}{r^2})\right]$
- 预处理从上往下的体积和表面积最小值,如果当前体积+往后的最小体积>n,那么直接结束
- 如果当前表面积+往后最小表面积>当前搜到的答案,那么直接结束
- 前dep-1层的体积可以表示为$n-v=\sum\limits_{i=1}^{dep-1}{h[i]*r[i]^2}$,表面积可以表示为$2\sum\limits_{i=1}^{dep-1}{h[i]*r[i]}$。由于$2\sum\limits_{i=1}^{dep-1}{h[i]*r[i]}=\frac{2}{r[dep]}\sum\limits_{i=1}^{dep-1}{h[i]*r[i]*r[dep]}\geq \frac{2}{r[dep]}\sum\limits_{i=1}^{dep-1}{h[i]*r[i]^2} \geq \frac{2(n-v)}{r[dep]}$,所以当$s+\frac{2(n-v)}{r[dep]}$大于搜索到的答案是剪枝即可。
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 25; 4 int n, m; 5 int minv[N], mins[N], r[N], h[N], ans = 1000000000; 6 void dfs(int now, int v, int s) { 7 if (v + minv[now] > n) return ; 8 if (s + mins[now] > ans) return ; 9 if (s + 2 * (n - v) / r[now + 1] >= ans) return ; 10 if (now == 0) { 11 if (n == v) ans = s; 12 return ; 13 } 14 for (register int nowr = min((int)sqrt(n - v), r[now + 1] - 1); nowr >= now; nowr--) 15 for (register int nowh = min((n - v) / nowr / nowr, h[now + 1] - 1); nowh >= now; nowh--) { 16 r[now] = nowr; 17 h[now] = nowh; 18 int t = 0; 19 if (now == m) t += nowr * nowr; 20 dfs(now - 1, v + nowr * nowr * nowh, s + 2 * nowr * nowh + t); 21 } 22 } 23 int main() { 24 cin >> n >> m; 25 for (register int i = 1; i <= m; ++i) { 26 minv[i] = minv[i - 1] + i * i * i; 27 mins[i] = mins[i - 1] + 2 * i * i; 28 } 29 r[m + 1] = h[m + 1] = 1000000000; 30 dfs(m, 0, 0); 31 cout << ans << endl; 32 return 0; 33 }