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 }
原文地址:https://www.cnblogs.com/ZhenghangHu/p/9371071.html
时间: 2024-10-08 15:16:47