由于深度一定(m),所以使用深度优先搜索,自上而下的设定蛋糕序号,最顶层的为第1层,……,最底层的蛋糕为第m层,很明显满足题目条件的前i层的(从顶层(也就是编号为1的层)开始计数)最小面积mins[i]和体积minv[i]是在该层的半径以及高度都为i时取得,如果采用一般的神搜肯定会超时,所以这题还需要剪枝,剪枝条件有(从m层向上搜,假设前dep层的体积为sumv,面积为sums,当前所得的最小面积为ans):
S = r1*r1 + 2 * (r1*h1 + r2*h2 + ...+ rm*hm)
N = r1*r1*h1 + r2*r2*hm + ... +rm*rm*hm
代码:
#include<iostream>
#include<string.h>
#define INF 999999999
#define MIN(a,b) ( a<b?a:b)
using namespace std;
int minv[30],mins[30];
int ans;
int n,m;
void dfs(int deep,int sums,int sumv,int r,int h)
{//cout<<n<<" "<<ans<<endl;
int realh;
if(deep == 0)
{
if(sums < ans && n == sumv) ans = sums;
return;
}
// cout<<sumv + sumv + minv[deep-1]<<" "<<sums + mins[deep-1]<<" "<<2*(n-sumv)/r+mins[deep-1]<<endl;
if(sumv + minv[deep-1] >n || sums + mins[deep-1] > ans || 2*(n-sumv)/r+sums>ans)
//三个剪枝,1:若m~deep-1层的总体积 + 1~deep层最小总体积 > n ,则返回
// 2:若m~deep-1层总面积 + 1~deep层的最小总面积 > 当前最小解,则返回
// 3:(n-sumv)/r是1~deep层蛋糕最小的可能r'*h,2*r'*h+sums是1~deep层最小可能总面积,所以若+m~deep-1层当前总面积>当前最优解,返回。
{ return;}
for(int i=r-1;i>=deep;i--)
{ //dfs的主体,i指deep层可能的半径 (最小一定为deep层数,最大为deep+1层r-1)
if(deep==m) sums=i*i; //sums初始化为r1*r1
realh=MIN((n-sumv-minv[deep-1])/(i*i) , h-1);
//h-1是该层蛋糕高度的默认值,(n-sumv-minv[deep-1])/(i*i)是可能的最小值
for(int j=realh;j>=deep;j--)
{
dfs(deep-1,sums + 2*i*j,sumv+i*i*j,i,j); //递归调用。
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
minv[0] = 0;
mins[0] = 1; //S=r1^2+2*(r1h1+r2h2...rmhm) r1至少为1,所以将mins[0]=1*1=1;
for(int i=1;i<=m;i++)
{ // mins 与 minv 分别代表第1层到第i层蛋糕的最小总面积、体积
mins[i]=mins[i-1]+2*i*i;
minv[i]=minv[i-1]+i*i*i;
}
ans = INF;
dfs(m,0,0,n,n); // m为搜索层次数,后面两个n代表最大r 、h(只有1层)
if(ans==INF) printf("0\n");
else printf("%d\n",ans);
}
return 0;
}