洛谷 P1731 [NOI1999] 生日蛋糕
Description
Solution
明显的就是搜索(但是我一点都不会写,我好蒻啊)。
首先一定是从下往上搜,如果从上往下的话就没有上界了,容易一搜到底。
然后再考虑这么几个优化:
-
当前体积 \(> \ n\),返回。
-
当前层数 \(> \ m\),返回。
-
当前面积 \(\geq\) 已经搜到的最大面积,返回。
-
当前体积 \(+\) 之后的最大体积 \(< \ n\),返回。
-
当前表面积 \(+\) 之后最大表面积 \(\geq\) 已经搜到的答案,直接返回(emm……有了这条前面那个好像就不用了,算了不管了)。
\(dfs\) 时,记录一下当前层数,剩余体积,当前侧面积。
半径,高度的枚举,从上一层的半径,高度开始,一直到还需要的层数即可,每层都留一个 1.
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
int n, m, ans = INF;
int r[30], h[30];
inline void dfs(int x, int v, int res){//x:层数 v:剩余体积 res:当前表面积
int tmp = m - x + 1;//还需要多少层
if(v < 0 || x > m + 1 || res >= ans) return;
if(!v && x == m + 1){
res += r[1] * r[1];
ans = min(ans, res);
return;
}
if(res + tmp + r[1] * h[1] > ans) return;
if(v - r[x - 1] * r[x - 1] * h[x - 1] * tmp > 0) return;
for(int i = r[x - 1] - 1; i >= tmp; i--){
for(int j = h[x - 1] - 1; j >= tmp; j--){
if(v - i * i * j >= 0 && x <= m){
r[x] = i, h[x] = j;
dfs(x + 1, v - i * i * j, res + (2 * i * j));
r[x] = h[x] = 0;
}
}
}
}
int main(){
scanf("%d%d", &n, &m);
r[0] = h[0] = (int)sqrt(n);
dfs(1, n, 0);
printf("%d\n", ans == INF ? 0 : ans);
return 0;
}