一.题目链接:
生日礼物
二.题目大意:
目标为做一个体积为 πn 层数为 m 的蛋糕.
并使得蛋糕从上到下,半径与高度均递增.
现往蛋糕上抹奶油(覆盖蛋糕表面,最底层的底面除外)
为了使花费最小,找出一种制作蛋糕的方法,使得奶油的覆盖面积最小.
输出奶油的最小覆盖面积 / π.
三.分析:
将蛋糕的层数从上到下编号为 1,2 ... m,记答案为 ans.
搜索时所需的状态有 当前的层数 i,当前的侧面积 s,当前的体积 πv.
易得:蛋糕的侧面积 == 蛋糕各层圆柱的侧面积 + 最底层圆柱的底面积.
由于层之间的半径与高度有约束条件,不妨记录各层的半径与高度.
① 上下界剪枝:
由于并使得蛋糕从上到下,半径与高度均递增
所以第 i 层蛋糕的半径与高度的下界均为 i,上界分别为
现从体积限制来分析上界,假设已选的蛋糕体积为 πv,第 i 层蛋糕的体积为
则
即:
综上所得:
② 优化搜索顺序:
倒序枚举,从下往上枚举.
这是因为底层蛋糕的体积大,先选体积大的,可以减少分支.
③ 可行性剪枝:
可以预先处理出,从上到下的最小体积前缀和 与 最小侧面积前缀和.
显然,当半径依次取 1,2 ... m ;高度依次取 1,2 ... m 时,两者取得最小值.
如果 ,则可剪枝.
④ 最优性剪枝一:
如果 ,则可剪枝.
⑤最优性剪枝二:(这里没想到啊。。)
利用体积与表面积的关系使用放缩法.
1 ~ i - 1 层的体积可表示为
1 ~ i - 1 层的侧面积可表示为
当 时,则可剪枝.
详见代码.
四.代码实现:
#include <set> #include <map> #include <ctime> #include <queue> #include <cmath> #include <stack> #include <bitset> #include <vector> #include <cstdio> #include <sstream> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define eps 1e-8 #define lc k * 2 #define rc k * 2 + 1 #define pi acos(-1.0) #define ll long long #define ull unsigned long long using namespace std; const int M = (int)1e2; const int mod = 99991; const int inf = 0x3f3f3f3f; int n, m; int ans = inf; int r[25], h[25]; int min_v_sum[25]; int min_s_sum[25]; /** r1 h1 r2 h2 2 1 4 6 **/ void dfs(int deep, int s, int v) { if(!deep) { if(v == n) ans = min(ans, s); return; } r[deep] = min((int)sqrt(n - v), r[deep + 1] - 1); while(r[deep] >= deep) { h[deep] = min((int)(double)(n - v) / r[deep] / r[deep], h[deep + 1] - 1) + 1; while(h[deep] > deep) { --h[deep]; if(v + min_v_sum[deep] > n) continue; if(s + min_s_sum[deep] > ans) continue; if(s + 2.0 * (n - v) / r[deep] > ans) continue; if(deep == m) s = r[deep] * r[deep]; dfs(deep - 1, s + 2 * r[deep] * h[deep], v + r[deep] * r[deep] * h[deep]); if(deep == m) s = 0; } --r[deep]; } } int main() { scanf("%d %d", &n, &m); for(int i = 1; i <= m; ++i) { min_s_sum[i] = min_s_sum[i - 1] + 2 * i * i; min_v_sum[i] = min_v_sum[i - 1] + i * i * i; } h[m + 1] = r[m + 1] = inf; dfs(m, 0, 0); if(ans == inf) ans = 0; printf("%d\n", ans); return 0; }