题目大意:Nπ体积m层的蛋糕,使得表面积最小
解题思路:将蛋糕从上到下编号1...m,从m层开始搜索,搜索过程中注意剪枝
三个剪枝条件:
1、已经搜索过的体积加上还未搜索过的最小体积不能比总体积n 大
2、已经搜索过的表面积加上还未搜索过的最小表面积不能比之前的最小总表面积best 大
3、n-sumv既所剩体积记作dv 还需要的表面积为s
s=2*ri*hi+2*r(i-1)*h(i-1)+... >=2*ri*hi*ri/r+2*r(i-1)*h(i-1)*r(i-1)/r+...
=2*dv/r(i从depth-1取,r为当前半径 ri/r<1)所以得到还需要的最小表面积s=2*(n-sumv)/r,如果最小的s和已经搜索过的表面积sums依然比best大 就不用继续搜索了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
const int inf=0xfffffff;
int n,m,minv[21],mins[21]; //minv[i]为从小到大的第i层的最小体积,最小表面积,从小到大(1...m)
int best=inf; //best 最小表面积
void DFS(int depth,int sumv,int sums,int r,int h) //深度优先搜索 自底m向上搜索 r h表示当前层得半径和高度
//sumv已经用的总体积 sums已经生成的总表面积
{
if(depth==0)
{
if(sumv==n&&sums<best) //搜索完成,更新最小表面积best
{
best=sums;
}
return;
}
if(sumv+minv[depth-1]>n||sums+mins[depth-1]>best||sums+2*(n-sumv)/r>=best) //剪枝如上所述
return;
for(int i=r-1;i>=depth;i--) //递减顺序枚举depth层半径的每一个可能值,这里第depth层的半径最小值为depth
{
if(depth==m)
sums=i*i; //俯视蛋糕底面积作为外表面积的初始值(总的上表面积,以后只需计算侧面积)
int maxh=min((n-sumv-minv[depth-1])/(i*i),h-1);
//maxh最大高度,即depth层蛋糕高度的上限,(n-sumv-minv[dep-1])表示第depth层最大的体积
for(int j=maxh;j>=depth;j--) //同理,第depth层的最小高度值为depth
{
DFS(depth-1,sumv+i*i*j,sums+2*i*j,i,j); //递归搜索子状态
}
}
}
int main()
{
while(scanf("%d%d",&n,&m) != EOF)
{
int rmax=(int)sqrt((double)n); //rmax初始半径 底层半径 最大值为sqrt(n)
int hmax=n; //hmax初始高度 高度最大为 n
minv[0]=mins[0]=0;
for(int i=1;i<=m;i++)
{ //初始化minv和mins数组
minv[i]=minv[i-1]+i*i*i; //从顶层(即第1层)到第i层的最小体积minv[i]成立时第j层的半径和高度都为j
mins[i]=mins[i-1]+2*i*i;
}
DFS(m,0,0,rmax,hmax);
if(best==inf)
best=0; //无解
printf("%d\n",best);
}
return 0;
}