搜索专题总结
来源:互联网 发布:pc机安装mac os x 编辑:程序博客网 时间:2024/05/26 07:29
经典例题随时可能更新… 其实这是不可能的,因为博主太懒了
迭代加深搜索
特点
描述:
人为加一个最大深度限定,再进行dfs,若在当前深度搜到了答案就输出,否则将最大深度增大。
优点:
①当题目所对应的搜索树是一棵无限树时(如经典例题1)。尽管在搜索过程中,有重复计算,但由于搜索树一般呈指数级增长,所以相对来说重复的计算量并不太大;
②当题目搜索的状态难以保存,或者空间复杂度较高时(如经典例题2)。它在搜索的实现上是dfs,结合其空间复杂度小和回溯的优点,就可以更好地处理问题。
经典例题
1.埃及分数
[Description]
在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好。 如: 19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4 + 1/6 + 1/180 19/45=1/5 + 1/6 + 1/18. 最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。
[Input Description]
a b
[Output Description]
若干个数,自小到大排列,依次是单位分数的分母。
[Sample Input]
19 45
[Sample Output]
5 6 18
思路
用迭代加深算法,每次再次调用dfs时,必须传递剩余分数的分子和分母,也可以顺便约分一下。另外在处理的时候,要计算一下分母的上界和下界即可。
代码
#include <iostream>#include <cstring>#include <cstdio>using namespace std;typedef long long lld;const int len=101;lld ans[len],t[len],depth;bool flag=false; lld max(lld a,lld b){return a>b?a:b;}lld min(lld a,lld b){return a<b?a:b;}lld gcd(lld a,lld b){return b?gcd(b,a%b):a;}void dfs(lld a,lld b,lld k){ if(k==depth+1||a<0) return ; if(b%a==0&&b/a>t[k-1]) { t[k]=b/a; if(!flag||t[k]<ans[k])//若没找到解,或找到的解的最小分数更大,即其分母更小 { memcpy(ans,t,sizeof(t)); flag=true; } return ; }//下一个分数<当前分数,下一个分数分母大于上一个 lld s=max(b/a,t[k-1]+1); lld e=(depth-k+1)*b/a; if(flag&&e>=ans[depth]) e=ans[depth]-1; for(lld j=s;j<=e;j++)//枚举下一个分数的分母 { s=s; t[k]=j; lld m=gcd(b,j); dfs((a*j-b)/m,b*j/m,k+1); t[k]-=j; }}int main(){ lld n,m; scanf("%d %d",&n,&m); t[0]=1; depth=0; while(!flag) { depth++; dfs(n,m,1); } for(int i=1;i<=depth;i++) printf("%d ",ans[i]); return 0;}
2.Tempter of the Bone II (HDU2128)
详细戳此
Astar及IDA*
特点
描述:
即在原搜索算法的基础上加上一个估价函数,对扩展出的节点估价,以此进行剪枝。
优点:
对当前状态估价,预先估计当前节点可以扩展出ans的可能性,再取最有可能的进行扩展。是一种比较高级的剪枝方法,能减去很多不必要的计算量。值得注意的是,有时候估价函数需要写得很精细,比如一些求最短路的题目,才能保证ans一定是最优;而有时候估价函数要写得粗糙一些(如经典例题3),才能更有效地减小估价的时间复杂度。
经典例题
3.Biggest Number (UVa11882)(A*)
详细戳此
4.Editing a Book (UVa 11212)(IDA*)
详细戳此
双向广搜
特点
描述
对bfs算法的一种改进。将起点和终点同时加入两个广搜队列中,每次对两个队列搜索一层,并进行标记。当在某种状态发生重合时,即找到了解。
优点
可以大大地减少搜索的状态数以及时间。因为搜索的状态数一般是随着层数指数级增长的,单向bfs需要搜ans层,双向bfs则只需搜两个大概ans/2层。
经典例题
5.Nightmare II (HDU3085)
题目大意
给你一张地图,描述了不能走的地方(然而ghost却可以走),ghost,M和G的位置。每个ghost每秒分裂占领所有离它两格距离的格子,M每秒移动3格,G每秒移动1格。询问M和G能否在ghost碰到他们之前(刚好相遇时碰到也不行)相遇,能则输出最短用时,不能输出-1。
思路
由于ghost是不受地形限制的,那么可以直接以曼哈顿距离来判断t时某格是否被占领,因此,我们就只需要考虑M和G的移动方案了,然后它就成了一道很裸的双向bfs题。
值得注意的是,为了使得我们每次操作只搜完一层,可以在开始搜之前将队列的元素个数保存一下,具体见代码部分。
代码
#include <iostream>#include <cstring>#include <cstdio>#include <queue>using namespace std;template <typename Tp> void read(Tp &x){ x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}const int size=810;int v[4][2]={{-1,0},{0,1},{1,0},{0,-1}};int z,n,m,mx,my,gx,gy,zx1,zy1,zx2,zy2,s;char map[size][size];bool flag,vis[size][size][2];queue<int> q[2];int abs(int x){return x>0?x:-x;}bool check(int x,int y,int s)//判合法性有点复杂,于是就写在外面了{ if(x<1||x>n||y<1||y>m||map[x][y]=='X') return false; if(abs(x-zx1)+abs(y-zy1)<=2*s) return false; if(abs(x-zx2)+abs(y-zy2)<=2*s) return false; return true;}bool bfs(int k,int s){ int x,y,xx,yy,num=q[k].size(); while(num--)//每次只搜一层 { x=q[k].front()>>10; y=(x<<10)^q[k].front(); q[k].pop(); if(!check(x,y,s))//ghost先走 continue; for(int i=0;i<4;i++) { xx=x+v[i][0],yy=y+v[i][1]; if((!check(xx,yy,s))||vis[xx][yy][k]) continue; if(vis[xx][yy][k^1])//判是否被另一个队列标记过 return true; vis[xx][yy][k]=true; q[k].push(xx<<10|yy); } } return false;}int main(){ read(z); while(z--) { read(n),read(m); flag=false; zx1=-1; for(int i=1;i<=n;i++,getchar()) for(int j=1;j<=m;j++) { map[i][j]=getchar(); if(map[i][j]=='M') mx=i,my=j; else if(map[i][j]=='G') gx=i,gy=j; else if(map[i][j]=='Z') { if(zx1==-1) zx1=i,zy1=j; else zx2=i,zy2=j; } } memset(vis,0,sizeof(vis)); while(!q[0].empty()) q[0].pop(); while(!q[1].empty()) q[1].pop(); q[0].push(mx<<10|my); q[1].push(gx<<10|gy); vis[mx][my][0]=true; vis[gx][gy][1]=true; s=1; while(q[0].size()||q[1].size()) { if(bfs(0,s)) {flag=true;break;} if(bfs(0,s)) {flag=true;break;} if(bfs(0,s)) {flag=true;break;} if(bfs(1,s)) {flag=true;break;} s++; } if(flag) printf("%d\n",s); else puts("-1"); } return 0;}
- SDAU 搜索专题 总结
- 搜索专题总结
- 搜索专题总结
- 专题二 搜索总结
- 专题二 搜索总结
- 总结搜索专题
- 专题二搜索总结
- 搜索专题总结
- 搜索专题总结
- 搜索专题总结
- 专题二 总结(搜索)
- 专题二总结 搜索算法
- 第二专题总结(搜索算法)
- ACM第二专题—搜索总结
- kuangbin专题一简单搜索总结
- 搜索专题
- 搜索专题
- 搜索专题
- Window环境下装linux(CentOS7)
- RMQ算法(一):ST表(Sparse Table)
- 设计模式学习(二)之工厂模式(简单工厂+工厂方法+抽象工厂)
- JDBC 和 Mybatis连接mysql数据库的时候,设置字符集编码
- @property (copy) NSMutableArray *array; 这个写法会出什么问题
- 搜索专题总结
- TP5与TP3.X大对比
- Bootstrap的下载
- Unity3D Image 组件附入图片问题
- idea打包jar的多种方式
- Unity3D设计模式之单例模式
- IO流/File
- 获取子物体数量---Transform.childCount
- python生成CMPL16类型随机定标测试数据并输出到文件