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 }

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9371071.html

时间: 2024-07-31 05:16:36

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

HDU 5025 Saving Tang Monk【bfs搜索】【北大ACM/ICPC竞赛训练】

bfs的难点在于怎么去表示一个问题的状态[也就是如何去判重] 1 #include<iostream> 2 #include<queue> 3 #include<cstring> 4 #include<map> 5 using namespace std; 6 7 struct node{ 8 int r,c; 9 int keys; 10 int kill;//记录当前杀死守卫的状态 11 int d;//时间 12 bool operator <

POJ Find the Winning Move【minmax搜索+alpha-beta剪枝】【北大ACM/ICPC竞赛训练】

1 #include<iostream> 2 using namespace std; 3 4 int row,col,chess; 5 char board[5][5]; 6 7 int minSearch(int i,int j,int alpha); 8 int maxSearch(int i,int j,int beta); 9 10 11 bool check(int r,int c){ 12 if( board[r][0]==board[r][1] && board

POJ 3436 ACM Computer Factory 【网络流】【北大ACM/ICPC竞赛训练】

我ac掉网络流的第一题! 先总结一下网络流的一些算法吧,首先是Ford-Fulkerson算法,这个算法是保证了众多网络流算法的[正确性],其他算法也是基于其[优化]得到的.Ford的算法在于引入"反向边"的概念,反向边就是反悔边,代表你给修正以前走了的边一个机会.为什么反向边是对的呢,凭空加进来一条边真的大丈夫吗,关于这个有相关正确性的证明,我也说不清楚只能直觉上去理解. 之后是Edmonds-Karp即最短增广路算法,顾名思义,每次都找到达汇点边数最少的增广路,由此避免一些特定的消

POJ 4979 海贼王之伟大航路 【状压dp】【北大ACM/ICPC竞赛训练】

该死的题让我想起来艾斯之死... 首先想到dp(i)代表从1到[i表示的这些岛屿]所花的最小时间,然后每次枚举最后一个岛屿以此缩小范围,但发现枚举了最后一个岛屿后没有办法转移,因为不知道倒数第二个岛屿是什么,随着倒数第二个岛屿的不同,时间的增加也会不同,也就是不具备[无后效性]. 因此想到再加一个参数去约束当前问题的状态,dp(i,j)代表1到[i代表的这些点]所需的最少时间,且这趟旅程的最后一个岛屿是j,这样就可转移了,每次枚举倒数第二岛屿:答案就是dp( (1<<n) -1,n ) 具体的

POJ 8471 切割回文 【dp】【北大ACM/ICPC竞赛训练】

1 #include<iostream> 2 #include<vector> 3 #define INF 100000 4 using namespace std; 5 6 string s; 7 char a[1005]; 8 vector<int> hui[1005];//hui[i]里的k指 k到i组成回文 9 int dp[1005];//dp[i]代表前i个字符要切几刀 10 11 int main(){ 12 int t; cin>>t; 13

POJ 1194 Zipper 【dp】【北大ACM/ICPC竞赛训练】

现在做dp题有点感觉了,以前估计会觉得这题很难,现在觉得这是道不是很水的水题 dp[i][j]代表A里前i个加上B里前j个能不能组成C的前i+j个. 至于怎么想到的呢,n是200,有1000组数据,所以猜测要dp二维,然后很容易就想到了. 这里再考虑到C[i+j]的这个元素肯定是由A[i]或B[j]组成(即A的最末尾或B的最末尾,因为要保证原来的order) 所以这就变成了dp[i][j] = dp[i-1][j] | dp[i][j-1]  (当然这是A[i]=B[j]=C[i+j])的情况.

poj 1011 Sticks 【DFS】+【剪枝】

题意:有未知根(长度一样)木棒(小于等于n),被猪脚任意的截成n段,猪脚(脑抽了)想知道被截之前的最短长度(我推测猪脚得了健忘症). 这道题光理解题意就花了好久,大意就是任意根被截后的木棒拼到一起,能不能组成s(<=n)根的相同的木棒, 例:数据 9  5 1 2 5 1 2 5 1 2 可以组成最短为6 的(5+1, 2+2+2)3根木棒. 策略:深搜. 不过要是传统的深搜的话,TLE妥妥的.所以要剪枝(所谓剪枝,就是多加几个限制条件). 话不多说直接上代码. 代码1: #include <

POJ 1321 棋盘问题 DFS搜索

简单搜索 练习一下回溯 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <sstream> 5 #include <string> 6 #include <algorithm> 7 #include <list> 8 #include <map> 9 #include <vector> 10 #inc

ACM/ICPC算法训练 之 分治法入门(画图模拟:POJ 2083)

题意:大致就是要求画出这个有规律的Fractal图形了= = 例如 1 对应 X 2 对应 X  X   X    X  X 这个题是个理解分治法很典型的例子(详情请参见Code) 分治法:不断缩小规模,以致把整个大问题分解为若干个可以直接处理的小问题,一般通过递归调用实现,可以用极简代码完成高复杂的工作,但空间与时间占用也相对较大. 1 //分治法画图 2 //Memory:880K Time:16 Ms 3 #include<iostream> 4 #include<cstring&