【NOI1999】生日蛋糕

Description

制作一个m层,体积为n的蛋糕,每层都是一个圆柱体,且下面的圆柱体的半径和高度必须大于上面的,求一种方案使得表面积最小(表面积不含底面积)

Solution

搜索题,我们考虑如下优化(假定当前搜索到第i层,已经用了体积v,表面积s):

  1. 为了减少搜索分支的数量,我们从下往上搜索,且从大到小枚举半径和长度
  2. 确定半径和高度的上下界:$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]$
  3. 预处理从上往下的体积和表面积最小值,如果当前体积+往后的最小体积>n,那么直接结束
  4. 如果当前表面积+往后最小表面积>当前搜到的答案,那么直接结束
  5. 前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 }
AC Code

 

posted @ 2019-08-08 10:57  AD_shl  阅读(265)  评论(0编辑  收藏  举报