详解 poj 1190 深搜 加 剪枝
来源:互联网 发布:申请网络记者 编辑:程序博客网 时间:2024/06/08 06:36
这道题用到 深搜 但是必须剪枝,否则一定超时~~
我把注释都写在程序上了,大家可以一边看一边理解~~
剪枝地方还是要说明一下:
遇到三种情况我们就不必搜下去了,需要剪掉:
(1) v + minv[m-1] > N 当前的体积,加上该层以上的最小体积都比总体积大,一定不符合条件!
(2) s + mins[m-1] > ans 当前的表面积加上该层以上的最小表面积比当前最优解大,一定不符合条件!
(3) 2*(N-v)/r + s >= ans 我们求到第m层的体积和表面积了,那么剩余的体积leftv(也就是该层以上的体积)就是 : N - v 。
我们现在假设m层以上是一个圆柱体,并且半径跟该层的半径 r 一样,那么 lefts = 2 * (N - v) / r (v = pi × r × r × h ;
s =2 × pi × r × h,根据这2个公式就可以推出) 但是!!实际情况是,该层以上的半径一定小于这一层
的半径 r !我们看到分母越小,整个的值就越大!所以,lefts 一定 大于 2×(N - v)/ r ( lefts > 2 * (N - v) / r 一定成立! )
而 lefts 还 等于 ans (最优解,即最终的答案) - s !! 也就是 lefts = ans - s > 2 * (N - v) / r
所以 2*(N-v)/r + s 一定小于 ans 即 2*(N-v)/r + s < ans
所以如果 2*(N-v)/r + s >= ans 就可以剪掉!
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define inf 10000000#define min(a,b) (a < b ? a : b)using namespace std;int N,M; //蛋糕的体积和层数 int minv[21],mins[21]; //用来表示蛋糕最小的体积和表面积 int ans; //最终结果 ,也就是最优解,也就是 Q的最优解,也就是 S的最优解 void init(){ //初始化2个数组,表示第i层上的最小体积和最小表面积 minv[0] = 0; mins[0] = 0;for(int i = 1; i <= 20; i++){ //体积和表面积最小的时候,就是从最上面一层r=h=1,接着下一层是r=h=2, minv[i] = minv[i-1] + i*i*i; //以此类推,第i层就是r=h=i 题目最多20层,所以这20层的最小体积和 mins[i] = mins[i-1] + 2*i*i; //最小表面积都可以求出来,这是最小的情况,不能再比他小了 !! } // 我们可以用这个做临界条件,进行剪枝 }void dfs(int m,int v,int s,int r,int h){ //从最下面一层向上深搜。好处就是可以知道最下面一层的半径,从而知道整个蛋糕的上表面积 //其中m表示当前层数,v表示当前体积,s表示当前表面积 if(m == 0){ //r代表当前层的半径,h表示当前层的高 if(v == N && s < ans){ ans = s; } return; } if( v + minv[m-1] > N || s + mins[m-1] > ans || 2*(N-v)/r + s >= ans) return; //剪枝 for(int i = r - 1; i >= m; i--){ //按照递减序列枚举第m层的所有可能情况, //最大的半径是r-1(r是上一层的半径,为了符合要求就是该层半径就是r-1 //最小半径是m,m是该层的最小表面积与最小体积时的半径(见init()的注释) if(m == M) s = i*i; //当前层是第M层时,它的半径就是整个蛋糕的上表面积,先加上再说~~ 这样以后只需加侧面积就可以了 int maxh = min((N-v-minv[m-1])/(i*i),h-1); //最大高度。第m层的最大体积的高:// ( n - v(该层的下面的层的体积) - minv[m-1] (该层的上面的层的最小体积))/ i*i (i是当前层的半径) for(int j = maxh; j >= m; j--){ //h的最大值与最小值同r情况一样 dfs(m-1,v+i*i*j,s+2*i*j,i,j); //每深搜一次减小一层,要加上该层的体积和侧面积 } }}int main(int argc, char *argv[]){init(); while(~scanf("%d%d",&N,&M)){ ans = inf; dfs(M,0,0,N+1,N+1); // 蛋糕的总体积是N,所以它的半径和高再高也不可能高于N,所以从N开始深搜 if(ans == inf) ans = 0; //如果最后ans的值没有变,说明找不到这样的解,S无解,输出0 printf("%d\n",ans); }return 0;}
- 详解 poj 1190 深搜 加 剪枝
- POJ 1190 生日蛋糕 搜索加剪枝
- poj 3714 分治加剪枝
- POJ 1190 生日蛋糕(深搜+剪枝)
- 深搜 加奇偶剪枝
- poj 1011 sticks 搜索加剪枝
- POJ 1416 DFS 加简单剪枝
- poj 1190 生日蛋糕(剪枝+深搜)
- poj 1190 生日蛋糕(深搜+剪枝技巧)
- poj 1190(DFS+剪枝)
- poj 1190 搜索+剪枝
- poj 1190(dfs剪枝)
- poj 1190(剪枝)
- poj 1190 dfs+剪枝
- POJ 1190(dfs剪枝)
- poj 1190 dfs+剪枝
- POJ 1011 sticks(深度优先加剪枝)
- poj 1190 生日蛋糕 dfs 剪枝
- facebook android sharesdk 分享清除授权代码
- JS动态加载数据绑定事件--delegate() 方法
- 20. Valid Parentheses
- Struts2学习笔记(一):简介和环境搭建
- iOS设计模式之策略模式
- 详解 poj 1190 深搜 加 剪枝
- 第二周项目3-小试循环
- Mysql基于FEDERATED存储引擎的远程表使用
- Java常见乱码问题总结
- C/C++面试题
- Func<TResult>和Func<TSource, TResult>
- BZOJ3757: 苹果树
- UVA11922 Permutation Transformer(Splay)
- online_judge_1515