POJ 6048 泰国佛塔 【dfs搜索】【疯狂剪枝!】【北大ACM/ICPC竞赛训练】

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 int volumn[25],minArea[25];//volumn[i]为第i层到第1层蛋糕所用最小体积
 6 int ans,n,m;                    //minArea[i]为第i层到第1层蛋糕所用【最小侧面积】 
 7 int area;//当前dfs状态所需要用的表面积
 8 
 9 int maxV(int level,int r,int h){//用level层蛋糕用的最多体积
10                                 //在第level层的半径为r,高度为h的情况下
11     int v=0;
12     for(int i=0;i<level;i++){
13         v+=r*r*h;
14         r--; h--;
15     }
16     return v;
17 }
18 
19 void dfs(int level,int remainVolumn,int maxRadius,int maxHeight){//用level层蛋糕去凑体积remainVolumn 
20                                                     //这一层蛋糕可枚举的最大半径是maxRadius,最高高度是maxHeight    
21 //    cout<<level<<" "<<remainVolumn<<" "<<maxRadius<<" "<<maxHeight<<endl;
22     if(level==0){
23         if(remainVolumn) return;
24          ans=min(ans,area);
25          return;
26     }
27     
28     if( volumn[level]>remainVolumn ) return;//如果剩下的层数用最小的体积去摆都会超体积 == 预测可行性剪枝 
29     if( area+minArea[level]>ans ) return;    //全局最优性剪枝 
30     if( maxRadius<level || maxHeight<level ) return;//可行性剪枝
31     if( remainVolumn>maxV(level,maxRadius,maxHeight)) return;//如果剩下的层数用尽可能大的体积去摆都用不完体积 == 预测可行性剪枝
32     
33     //剪完枝开始枚举第level层的【半径】和【高度】 
34     for(int i=maxRadius;i>=level;i--){
35         if( level==m ) area=i*i;//把底面积考虑上
36         for(int j=maxHeight;j>=level;j--){
37             area+=2*i*j;
38             if( remainVolumn-i*i*j>=0) {
39             //    cout<<"!!! "<<i<<" "<<j<<endl;
40                 dfs(level-1,remainVolumn-i*i*j,i-1,j-1);
41             }
42             area-=2*i*j;
43         }
44     }
45     
46 }
47 
48 int main(){
49     
50     while( scanf("%d",&n)!=EOF ){
51         cin>>m;
52         ans=(1<<30);
53     
54         for(int i=1;i<=m;i++){
55             volumn[i] = volumn[i-1] + i*i*i;
56             minArea[i] = minArea[i-1] + 2*i*i;
57         }
58         area=0;
59         
60         //半径最大时是第一层蛋糕体积最大且高度最小 
61         //1.什么时候体积最大 ==> 第二层到第m层都用尽可能小的体积
62         //2.什么时候高度最小 ==> 第二层到第m层每层高度尽可能小高度 ==>第i层的最小高度是i 
63         int maxRadius = sqrt( (n-volumn[m-1])/m );
64         
65         //高度最高是第一层蛋糕体积最大且半径最小
66         //第i层半径最小是i 
67         int maxHeight = (n-volumn[m-1]) / (m*m) ;
68         
69         dfs(m,n,maxRadius,maxHeight);
70         
71         if(ans==(1<<30)) cout<<0<<endl;
72         else cout<<ans<<endl;
73     }
74 
75     
76     return 0;
77 }

猜你喜欢

转载自www.cnblogs.com/ZhenghangHu/p/9371071.html
今日推荐