UVA11196 Birthday Cake
根据题目给出的条件,确定下来这道题是爆搜加剪枝。
同时此题为 P1731 [NOI1999] 生日蛋糕 的强化版。
似乎在 剪贴板 里排版会更好。
基本公式
注意,从这里开始,所有公式将忽略
设最底层为第
同时体积公式为:
图示
这个图对理解下列公式有帮助。
剪枝优化
1.优化搜索顺序
- 层间:从底部向上枚举。
- 层内:先枚举半径再枚举高(半径相对于高来说对体积的影响较大),半径由大到小,高度由大到小。
2.可行性剪枝
考虑第
设总体积为
我们考虑第
根据图示,第
则
故公式可以化为
在代码中,此时
当然,还要剪枝。
考虑表面积公式和体积公式之间的关系
将
3.最优性剪枝
如果当前的累计值加上之后的最小值大于等于目标值,则可以剪枝。
放到代码中,就是当前的体积加上之后的最小体积还大于
至此,所有剪枝就讲完了,码代码应该不是什么大问题。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 25;
int n, m;
int minv[N], mins[N], R[N], H[N];
int res = 1e9;
void dfs(int u, int v, int s) {
if (v + minv[u] > n) return;
if (s + mins[u] >= res) return;
if (s + 2 * (n - v) / R[u + 1] >= res) return;
if (u == 0) {
if (v == n) res = min(res, s);
return;
}
for (int r = min(R[u + 1] - 1, (int)sqrt((n - v - minv[u - 1]) / u)); r >= u; r--) {
for (int h = min(H[u + 1] - 1, (n - v - minv[u - 1]) / r / r); h >= u; h--) {
H[u] = h, R[u] = r;
int t = u == m ? r * r : 0;
dfs(u - 1, v + r * r * h, s + 2 * r * h + t);
}
}
}
int cas;
int main() {
while (cin >> n >> m) {
cas++;
res = 1e9;
if (n == 0) break;
memset(minv, 0, sizeof minv);
memset(mins, 0, sizeof mins);
for (int i = 1; i <= m; i++) {
minv[i] = minv[i - 1] + i * i * i;
mins[i] = mins[i - 1] + 2 * i * i;
}
R[m + 1] = H[m + 1] = 2e9;
dfs(m, 0, 0);
cout << "Case " << cas << ": " << ((res == 1e9) ? 0 : res) << endl;
}
}
//此代码成功拿到uva11196最优解!