广度优先搜索总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了广度优先搜索总结相关的知识,希望对你有一定的参考价值。
广度优先搜索是对无向图以逻辑上的树的形式从根节点开始进行的逐层遍历。
当题目所求为路径某属性最小的解时适用广度优先搜索,因为如果能使逻辑上的树的层数和所求的最小的属性严格一致,逐层遍历到终点时必然为其属性最小值。
算法实现:基于(优先)队列先进先出的特性,实现优先遍历上层节点,通过标记数组保证访问过的点不被多次访问。
将根节点入队,在while(!q.empty())循环中将队首取出,并建立其子节点信息,如果子节点是合法的就入队并标记,直到找到答案或队列为空表示未找到。
注意问题:1、初始化标记数组为0(当用普通队列实现优先队列功能时,标记数组初始化为INF),使用前清空队列。
2、设置标记在入队处,这样能保证被访问过的节点不再被访问。
3、注意边界处理,边界判断在对地图判断之前,防止下标越界。
带注释模板:
HDU-2717
1 #include <iostream> 2 #include <queue> 3 #include <string.h> 4 using namespace std; 5 int n,m;//n是初始位置,m是终点 6 int vis[200005];//用来记录是否访问过,未访问为0访问过就置1 7 struct Node 8 { 9 int pos;//记录当前位置 10 int time;//记录当前用时 11 }; 12 queue <Node> q; 13 bool ok(Node dep) 14 { 15 if(dep.pos<0||dep.pos>100000)//这道题目最远是100000,所以超过这个就可以不考虑了 16 return false; 17 if(vis[dep.pos]==1)//如果被访问过就不去 18 return false; 19 vis[dep.pos]=1;//如果可以走,就把它标记一下,表示我走过了,防止再走 20 return true; 21 } 22 int bfs() 23 { 24 while(!q.empty())//如果队列非空就循环,直到找到终点 25 { 26 Node now,next;//新建两个节点,一个是当前节点,一个是下一个位置的节点 27 now=q.front();//把队列第一个元素传给now 28 q.pop();//删除第一个元素,根据队列特性,后续元素会自动往前推 29 if(now.pos==m) 30 { 31 return now.time;//如果到达终点,便返回当前时间,函数结束 32 } 33 next=now;//设置next的信息,分别是+1,*2-,-1,时间在now基础上+1 34 next.pos++; 35 next.time++; 36 if(ok(next))//ok函数判断这个点能不能走 37 q.push(next);//如果可以就入队 38 next=now; 39 next.pos*=2; 40 next.time++; 41 if(ok(next)) 42 q.push(next); 43 next=now; 44 next.pos--; 45 next.time++; 46 if(ok(next)) 47 q.push(next); 48 } 49 } 50 int main() 51 { 52 while(cin>>n>>m) 53 { 54 memset(vis,0,sizeof(vis)); 55 while(!q.empty()) 56 q.pop(); 57 Node st;//建立起点信息 58 st.pos=n; 59 st.time=0; 60 vis[n]=1; 61 q.push(st);//入队 62 cout<<bfs()<<endl; 63 } 64 return 0; 65 }
BFS相关题目(补充中...):
HDU-2612 Find a way
一对好基友要在KCF面基,找出总用时最少的KCF地点,只要分别以两个人为起点去找出所有的KCF并记录到每个KCF的最短时间,然后求下最小值就行。
注意这里的总用时是两者用时之和,且不像一般广搜搜到就结束,这里需要把所有KCF搜完再结束。
#include <iostream> #include <queue> #include <string.h> #include <stdio.h> using namespace std; struct Node { int x,y; int time; }; queue <Node> q; int n,m,cot; char _map[215][215]; int vis[215][215]; int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; int ktime[215][215]; bool ok(Node now) { if(now.x<=0||now.x>m||now.y<=0||now.y>n) return false; if(vis[now.y][now.x]==1) return false; if(_map[now.y][now.x]==‘#‘) return false; return true; } void bfs(int flag,int ord) { Node now,next; while(!q.empty()) { now=q.front(); q.pop(); if(_map[now.y][now.x]==‘@‘) { ktime[now.y][now.x]+=now.time; } for(int i=0;i<4;i++) { next.x=now.x+dir[i][0]; next.y=now.y+dir[i][1]; next.time=now.time+1; if(ok(next)) { vis[next.y][next.x]=1; q.push(next); } } } } int main(int argc, const char * argv[]) { while(cin>>n>>m) { while(!q.empty()) q.pop(); memset(_map,‘0‘,sizeof(_map)); memset(ktime,0,sizeof(ktime)); memset(vis,0,sizeof(0)); int i,j; Node M,Y; cot=0; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { cin>>_map[i][j]; if(_map[i][j]==‘Y‘) { Y.x=j; Y.y=i; Y.time=0; } if(_map[i][j]==‘M‘) { M.x=j; M.y=i; M.time=0; } if(_map[i][j]==‘#‘) cot++; } } while(!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); vis[Y.y][Y.x]=1; q.push(Y); bfs(0,0); while(!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); vis[M.y][M.x]=1; q.push(M); bfs(1,0); int _min=11111111; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { if(_map[i][j]==‘@‘&&ktime[i][j]) { if(_min>=ktime[i][j]) _min=ktime[i][j]; } } } cout<<_min*11<<endl; } return 0; }
HDU-1548 A strange lift
电梯有向上、向下一层、到达Ki层的功能(请给我一台),简单遍历一下找到终点就行,注意下边界。
#include <iostream> #include <string.h> #include <queue> using namespace std; int n,a,b,num[205],mint; int vis[205]; struct node { int pos,time; }; queue <node> q; bool ok(node now) { if(now.pos<=0||now.pos>n) return false; if(vis[now.pos]==1) return false; return true; } void bfs() { while(!q.empty()) { node now,next; now=q.front(); q.pop(); vis[now.pos]=1; if(now.pos==b) { mint=now.time; return; } next=now; next.pos+=num[now.pos]; next.time++; if(next.pos==b) { mint=next.time; return; } if(ok(next)) q.push(next); next=now; next.pos-=num[now.pos]; next.time++; if(next.pos==b) { mint=next.time; return; } if(ok(next)) q.push(next); } } int main() { while(cin>>n) { if(n==0) break; cin>>a>>b; mint=-1; memset(num,0,sizeof(num)); memset(vis,0,sizeof(vis)); while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) cin>>num[i]; node st; st.pos=a; st.time=0; q.push(st); bfs(); cout<<mint<<endl; } return 0; }
HDU-1253 胜利大逃亡
三维空间的搜索,判断条件比较多,注意不要写错了。据说终点可能是不能走的,可以在主函数单独判断一下,省的搜索了,不过要是测试数据不给面子,优化不了多少时间。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <queue> 5 #include <cmath> 6 using namespace std; 7 int _map[55][55][55]; 8 int vis[55][55][55]; 9 int dir[6][3]={{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}; 10 int mintime,time; 11 int n,m,s; 12 struct block 13 { 14 int x,y,z; 15 int time; 16 }; 17 bool ok(block now) 18 { 19 if(abs(now.x-s+1)+abs(now.y-m+1)+abs(now.z-n+1)+now.time>time) 20 return false; 21 if(vis[now.z][now.y][now.x]==1) 22 return false; 23 if(_map[now.z][now.y][now.x]==1) 24 return false; 25 if(now.y<0||now.y>=m||now.z<0||now.z>=n||now.x<0||now.x>=s) 26 return false; 27 return true; 28 } 29 queue<block> q; 30 int bfs() 31 { 32 block now; 33 block next; 34 while(!q.empty()) 35 { 36 now=q.front(); 37 q.pop(); 38 if(now.z==(n-1)&&now.y==(m-1)&&now.x==(s-1)&&now.time<=time) 39 return now.time; 40 for(int i=0;i<6;i++) 41 { 42 next=now; 43 next.x+=dir[i][0]; 44 next.y+=dir[i][1]; 45 next.z+=dir[i][2]; 46 if(ok(next)) 47 { 48 next.time++; 49 vis[next.z][next.y][next.x]=1; 50 q.push(next); 51 } 52 } 53 } 54 return -1; 55 } 56 57 int main() 58 { 59 int t; 60 cin>>t; 61 while(t--) 62 { 63 memset(_map,0,sizeof(_map)); 64 memset(vis,0,sizeof(vis)); 65 while(!q.empty()) 66 q.pop(); 67 scanf("%d %d %d %d",&n,&m,&s,&time); 68 int i,j,k; 69 for(i=0;i<n;i++) 70 { 71 for(j=0;j<m;j++) 72 { 73 for(k=0;k<s;k++) 74 { 75 scanf("%d",&_map[i][j][k]); 76 } 77 } 78 } 79 if(_map[n-1][m-1][s-1]==1) 80 { 81 printf("-1\n"); 82 continue; 83 } 84 block st; 85 st.x=st.y=st.z=st.time=0; 86 q.push(st); 87 mintime=bfs(); 88 printf("%d\n",mintime); 89 } 90 return 0; 91 }
未完待续...(若有错误、不足之处望谅解并指出)
以上是关于广度优先搜索总结的主要内容,如果未能解决你的问题,请参考以下文章