题意:原谅我的懒
分析:
搜索即可。
基本思路:枚举每层的半径和高,dfs中传5个参数,当前的层,现有表面积,现有体积,当前层下一层的高度和半径。
剪枝:
1.从下往上搜索,减小搜索树。
2.枚举高度和半径时,倒序枚举,减小搜索树。
3.上下界,详见代码。
4.最优性剪枝:预处理1-dep层的最小体积和表面积,进行剪枝。
5.最优性剪枝(不好想):用体积和表面积的关系剪枝。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int inf = 0x3fffffff;
int n,m,ans=inf,vv[25],ss[25];
void dfs(int dep, int s, int v, int h, int r) {
if(!dep) {if(v == n) ans = min(ans, s+r*r); return;}
if(v+vv[dep] > n || s+ss[dep] >= ans || s+2*(n-v)/r+r*r >= ans) return;
for(int i = min(r-1, (int)sqrt((double)(n-v)/dep)); i >= dep; i--)
for(int j = min(h-1, (n-v)/(i*i)); j >= dep; j--)
dfs(dep-1, s+2*i*j+(dep==m?0:r*r-i*i), v+i*i*j, j, i);
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) vv[i] = vv[i-1]+i*i*i, ss[i] = ss[i-1]+3*i*i-(i-1)*(i-1);
dfs(m, 0, 0, inf, inf);
printf("%d", ans == inf ? 0 : ans);
return 0;
}
做了十几道深搜题了,来总结一下:
1.基本思路是怎么表示状态,可以传参,或用全局数组。
2.枚举的上下界剪枝,比如一些显然不可能的(参照上面的上下界剪枝),还有常见的比如放东西,放到空的里面都是一样的,就直接枚举到第一个空的停下即可。
3.避免重复搜索,如用vis数组判重,“木棍”中某长度的搜索失败不再尝试其他相同长度的等。
4.搜索顺序剪枝,一般都是为了减小搜索树,常用的如倒序,排序等。
5.答案很小或给定范围时,可以考虑用迭代加深。
6.当一个决策成功时,可能其他决策就显然不对了(贪心剪枝),如拦截导弹,如果能够用以前的系统拦截,则不需要新建一个系统。
7.可行性剪枝,如“木棍”,是总和约数再进行搜索和最长木棍搜索失败,直接返回。
8.最优性剪枝,见上。