POJ 1190生日蛋糕(隐式BFS)

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


你可能感兴趣的:(POJ 1190生日蛋糕(隐式BFS))