描述 |
---|
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。 |
设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。 |
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。 |
令Q = Sπ,请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。 |
(除Q外,以上所有数据皆为正整数) |
输入 |
---|
有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。 |
输出 |
仅一行,是一个正整数S(若无解则S = 0)。 |
样例输入 |
100 |
2 |
Sample Output |
68 |
圆柱公式 |
---|
体积V = πR 2H |
侧面积A’ = 2πRH |
底面积A = πR 2 |
|
---|
杂记 |
2020年3月4日,我接触此题,并为这道题花了整整一天的时间来做,从纠结于用BFS还是DFS,一开始还是想的是D,后来看到数据量有点大,就像是不是应该用BFS,最后DFS和BFS都写了,都用了剪枝,就是跟求极限情况。如果这一层的所选的半径和高度所造成的最小体积+现在所有的体积都大于N就减去。我这天都没意识到一个问题就是搜索的顺序,我一开始是从上往下搜的,觉得第一层半径和高度都从1开始,毕竟有个清晰的起点,也很自信的搜下去了。确实这个剪枝能剪掉一部分情况,后来上网搜索了这道题,又发现可以最优性剪枝,如果当前层所产生的最小表面积加上现有的表面积都大于ans,就剪掉。确实,加上这个剪枝后,10000 的3,4 ,5都很快出来了,还不够。我实在想不到还能怎么优化,就有上网查了这道题,发现还有一个很强的剪枝,说如果当前剩余体积整个做成一个圆柱后,这样增加的表面积是最小的,但这是对于从下往上构造的情况才有效,我从上往下构造蛋糕,口径不断变大,高度不断增加,如果要修改最上层的话,回溯太麻烦了。 |
正确思路 |
---|
知道真相的我眼泪掉下来。。应改从下往上搜,起始半径为sqrt(N)+1,起始高度应该为N+1,这是很大的值,因为一开始肯定有很多值不满足条件,最下面一层的高度太高,那么加起来的最小体积超N,或者半径太大,最小体积超N。这一层的R和H就不断往小走,如果H太小就说明够不到N,具体看注释把 |
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n, m, q;
int ans;
int minv[22];
int leftS[22];
#define DEBUG
void dfs(int ci,int nv,int ns,int r,int h) {
#ifdef DEBUG
#endif
if (ci == 0 &&nv==n) {
ans = min(ans, ns);
return;
}
if (leftS[ci] + ns >= ans) return;
if (minv[ci] + nv > n) return;
int mrv;
int nr, nh;
int avgV = (n - nv) / ci;
for (nr = r - 1; nr>=ci; nr--) {
for (nh = h - 1; nh>=ci; nh--) {
int curV = nr*nr*nh;
if (curV < avgV) break;
if (curV > n-nv) continue;
mrv = 0;
for (int i = 1; i<ci; i++) {
mrv += (nr - i)*(nr - i)*(nh - i);
}
if (n - nv - curV > mrv) break;
if (ci == m) ns = nr*nr;
dfs(ci - 1, nv + curV, ns + 2 * nr* nh,nr,nh);
}
}
}
int main() {
for (int j = 1; j <= 20; j++) {
for (int i = 0; i < j; i++) {
leftS[j] += (j - i)*(j - i);
minv[j] += (j - i)*(j - i)*(j - i);
}
}
while (scanf("%d %d", &n, &m) != EOF) {
ans = 1e9;
dfs(m, 0, 0, sqrt((double)n)+1, n+1);
printf("%d\n", ans==1e9?0:ans);
}
return 0;
}