BFS与双向BFS Knight Moves(经典棋盘问题!!!)
2017-07-16 10:16
381 查看
题意:棋盘上移动判断多少步可以到达(确认是可以到达的)
思路:BFS广度搜索,每一个点最多有8个可能的位置
然后依次“枚举”即可。
该版本为队列中存贮的为int 型的数据,每一组数据要压入队列3次,相应的出队列也是三次
此版本是使用了结构体之后,把之前版本的一组三个数据放在结构体node中,队列类型为node ,所以一组数据入出队列以次即可
下面是双向BFS的数组版本,但是有bug,这里给出代码的大体思路。
此为结构体型的双向BFS,值得学习的不仅仅是双向BFS的思路,还有将起始BFS与末尾BFS写在一起的思路。
这是这份代码最值得学习的,起始末尾BFS通用的地方通过函数传递过去,如果需要改变数值的话,加上引用即可
双向BFS:起始BFS一层,末尾BFS一层,在循环当中判断是否相遇,直到flag为0.
此为效率最高的算法,当面对数据范围较大的题目时,优势将明显体现出来
思路:BFS广度搜索,每一个点最多有8个可能的位置
然后依次“枚举”即可。
该版本为队列中存贮的为int 型的数据,每一组数据要压入队列3次,相应的出队列也是三次
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; //定义方向数组dir 为8个方向的偏移量 struct position { int x,y; }; position dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}}; char c[6]; int a[6]; queue<int>que; bool vis[9][9]; int ans; bool in(int a,int b){ if(a>0&&a<=8&&b>0&&b<=8) return true; return false; } int BFS() { int col,row;//定义列,行,计数器 ans=0; que.push(a[0]); //起点列 que.push(a[1]); //起点 行 que.push(ans); //起点步数 vis[a[1]][a[0]]=true; while(!que.empty()) { col=que.front(); que.pop(); row=que.front(); que.pop(); ans=que.front(); que.pop();//取编号 if(col==a[2]&&row==a[3]) //到达目标状态 return ans; for(int i=0;i<8;i++) //向8个方向扩展 { //扩展入队列 if(in(row+dir[i].x,col+dir[i].y)&&!vis[row+dir[i].x][col+dir[i].y]){ que.push(col+dir[i].y); que.push(row+dir[i].x); que.push(ans+1); vis[row+dir[i].x][col+dir[i].y]=true; } } } } int main() { int i,j; while(gets(c)) { while(!que.empty()) que.pop(); for(i=0;i<=8;i++) for(j=0;j<=8;j++) vis[i][j]=false; a[0]=c[0]-'a'+1; a[1]=c[1]-'0'; a[2]=c[3]-'a'+1; a[3]=c[4]-'0'; BFS(); printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans); } return 0; }
此版本是使用了结构体之后,把之前版本的一组三个数据放在结构体node中,队列类型为node ,所以一组数据入出队列以次即可
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; struct node { int x,y,sum; }; struct position { int x,y; }; position dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}}; char c[6]; int a[6]; queue <node> que; //什么类型<>中就放入什么 bool vis[10][10]; int ans; bool in(int x,int y) { if(x<=8&&x>0&&y>0&&y<=8) return true; return false; } int BFS() { ans=0; node t,m; t.x=a[0]; t.y=a[1]; t.sum=ans; memset(vis,0,sizeof(vis)); //初始化访问数组 vis[t.x][t.y]=1; //初始点初始化 que.push(t); //初始点压入队列 while(!que.empty()) { t=que.front(); que.pop(); if(t.x==a[3]&&t.y==a[4]) { ans=t.sum; // printf("%d",ans); return ans; //到达目标位置,返回 } for(int i=0;i<8;i++) { if(in(t.x+dir[i].x,t.y+dir[i].y)&&!vis[t.x+dir[i].x][t.y+dir[i].y]) { m.x=t.x+dir[i].x; m.y=t.y+dir[i].y; m.sum=t.sum+1; que.push(m); } } } } int main() { while(gets(c)) { while(!que.empty()) que.pop(); a[0]=c[0]-'a'+1; a[1]=c[1]-'0'; a[3]=c[3]-'a'+1; a[4]=c[4]-'0'; BFS(); printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans); } return 0; }
下面是双向BFS的数组版本,但是有bug,这里给出代码的大体思路。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; struct position { int x,y; }; //定义方向数组dir position dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}}; char c[6]; int a[6]; queue<int> que1,que2; int vis[9][9]; int cnt,ans,ans1,ans2; int flag; bool in (int a,int b) { if(a>0&&a<=8&&b>0&&b<=8) return true; return false; } //此题目中输入的行列顺序为先列后行 void single_BFS1() { int col,row,stp,i; col=que1.front(); que1.pop(); row=que1.front(); que1.pop(); stp=que1.front(); que1.pop(); for(i=0;i<8;i++) { if(in(row+dir[i].x,col+dir[i].y)&&vis[row+dir[i].x][col+dir[i].y]!=1) { ans1=stp+1; if(vis[row+dir[i].x][col+dir[i].y]==2) { flag=0; ans=ans1+ans2; return ; } } que1.push(col+dir[i].y); que1.push(row+dir[i].x); que1.push(ans2); vis[row+dir[i].x][col+dir[i].y]=1; } } void single_BFS2() { int col,row,stp,i; col=que2.front(); que2.pop(); row=que2.front(); que2.pop(); stp=que2.front(); que2.pop(); for(i=0;i<8;i++) { if(in(row+dir[i].x,col+dir[i].y)&&vis[row+dir[i].x][col+dir[i].y]!=2) { ans2=stp+1; if(vis[row+dir[i].x][col+dir[i].y]==1) { flag=0; ans=ans1+ans2; return ; } } que2.push(col+dir[i].y); que2.push(row+dir[i].x); que2.push(ans2); vis[row+dir[i].x][col+dir[i].y]=2; } } int main() { while(gets(c)) { while(!que1.empty()) que1.pop(); while(!que2.empty()) que2.pop(); for(int i=0;i<=8;i++) for(int j=0;j<=8;j++) vis[i][j]=0; a[0]=c[0]-'a'+1; a[1]=c[1]-'0'; a[2]=c[3]-'a'+1; a[3]=c[4]-'0'; flag=1; ans=ans1=ans2=0; int step=0; que1.push(a[0]);//起点入队列 que1.push(a[1]); que1.push(step); vis[a[1]][a[0]]=1; que2.push(a[2]);//终点入队列 que2.push(a[3]); que2.push(step); vis[a[3]][a[2]]=2; if(a[0]==a[2]&&a[1]==a[3]){ printf("To get from %c%c to %c%c takes 0 knight moves.\n",c[0],c[1],c[3],c[4]); } else{ while(flag) { cnt=que1.size()/3; //统计本层节点个数,正向BFS while(cnt--&&flag) //本层节点为扩展完,且未相遇标志flag为true single_BFS1(); //正向BFS cnt=que2.size()/3;//统计本层节点个数,正向BFS while(cnt--&&flag)//本层节点为扩展完,且未相遇标志flag为true single_BFS2();//反向BFS } printf("%d %d %d\n",ans,ans1,ans2); //printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans); } } return 0; }
此为结构体型的双向BFS,值得学习的不仅仅是双向BFS的思路,还有将起始BFS与末尾BFS写在一起的思路。
这是这份代码最值得学习的,起始末尾BFS通用的地方通过函数传递过去,如果需要改变数值的话,加上引用即可
#include <cstdio> #include <queue> #include <algorithm> #include <cstring> using namespace std; struct position { int x,y; }; struct node { int x,y,sum; }; queue <node> que1,que2; position dir[8]={{2,1},{2,-1},{-2,1},{-2,-1},{1,-2},{1,2},{-1,-2},{-1,2}}; int vis[10][10]; //1代表的是起始点的BFS 2代表的是结束点的BFS int flag,ans,ans1,ans2; char c[6]; int a[6]; bool in(int a,int b) { if(a>0&&a<=8&&b>0&&b<=8) return true; return false; } void DBFS(queue<node>&que,int m,int n,int &res1,int res2) {//m为起始 末位BFS vis所对应的 ,n则和m相对 //res为起始 末尾BFS所对应的ans node now,next; int x,y,stp; now=que.front(); que.pop(); x=now.x,y=now.y; stp=now.sum; for(int i=0;i<8;i++) //从8个方向扩展 { int row=now.x+dir[i].x,col=now.y+dir[i].y; if(in(row,col)&&vis[row][col]!=m) { res1=stp+1; if(vis[row][col]==n) //判断是否“相遇” { ans=res1+res2; flag=0; return ; } next.x=row,next.y=col; next.sum=res1; que.push(next); //将next压入队列 vis[row][col]=m; //进行标记 } } } int main() { while(gets(c)) { while(!que1.empty()) que1.pop(); while(!que2.empty()) que2.pop(); memset(vis,0,sizeof(vis)); a[0]=c[0]-'a'+1; a[1]=c[1]-'0'; a[2]=c[3]-'a'+1; a[3]=c[4]-'0'; flag=1; ans=ans1=ans2=0; node s,e; //起始点与结束点 s.x=a[1],s.y=a[0]; s.sum=0; que1.push(s); vis[s.x][s.y]=1; e.x=a[3],e.y=a[2]; e.sum=0; que2.push(e); vis[e.x][e.y]=2; //数据的初始化完成 if(a[1]==a[3]&&a[0]==a[2]) printf("To get from %c%c to %c%c takes 0 knight moves.\n",c[0],c[1],c[3],c[4]); else { while(flag) { int num1=que1.size(); //统计本层的节点个数 while(num1--&&flag) //本层节点为扩展完且标识符flag为1 DBFS(que1,1,2,ans1,ans2); int num2=que2.size(); //统计本层的节点个数 while(num2--&&flag) //本层节点为扩展完且标识符flag为1 DBFS(que2,2,1,ans2,ans1); } printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans); } } }
双向BFS:起始BFS一层,末尾BFS一层,在循环当中判断是否相遇,直到flag为0.
此为效率最高的算法,当面对数据范围较大的题目时,优势将明显体现出来
相关文章推荐
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- BFS与双向BFS Knight Moves(经典棋盘问题!!!)
- pku 1077 Eight 经典8数码问题 单向BFS + A* BFS + 双向BFS
- 八数码问题(A*&&双向BFS)
- POJ1077、HDU1043 Eight 八数码问题:双向BFS、A*
- poj 棋盘问题(经典DFS)(枚举)
- 双向BFS的优势(跳马问题)
- 双向BFS解八数码问题: POJ 1077
- 经典问题六.【二维的区间dp】棋盘分割 poj 1191
- poj 棋盘问题(经典DFS)(枚举)
- 经典迷宫问题BFS
- 算法提高 学霸的迷宫 经典广搜bfs问题
- POJ 1321 经典棋盘问题 的搜索和状态压缩解法
- poj 棋盘问题(经典DFS)(枚举)
- 八数码问题 经典搜索 bfs
- DFS深度优先搜索(2)--poj1321(棋盘问题 经典DFS)