由于深度一定(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; }