记录----第一次使用BFS(广度搜索)学习经验总结
学习经验记录与分享——
最近在学习中接触到了一种解决最短路径的实用方法----BFS(广度搜索),在这里总结并分享一下第一次学习的经验。
首先第一个要了解的是"queue"(队列函数),BFS以这个为核心展开,我先把队列函数常用用法写一下:
1.queue<队列数据类型> 队列名;例如:queue<int> Q;意思是创建一个存入int类型元素的队列。(接下来队列名都以Q示范)
2.Q.push(存入相应类型的元素名);
3.Q.pop();释放队列中的第一个元素
4.Q.front();访问队列中的第一个元素
5.Q.back();访问队列中的最后一个元素
6.Q.empty();如果队列元素为空,则返回真值,相反若不为空则返回假值
7.Q.size();队列元素个数
在这里讲一下队列的基本概念,可以简单说成两个门,一个入口,一个出口,先入队列的最靠近出口,也就是第一个元素,可以看下这个代码:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int main (int argc, const char * argv[]) 6 { 7 queue<int> Q; 8 for(int i=0;i<10;i++) 9 { 10 Q.push(i); //入队 11 } 12 for(int j=0;j<10;j++) 13 { 14 cout<<Q.front()<<" "; //打印 15 Q.pop(); //弹出 16 } 17 return 0; 18 }
这行代码具体意思就是先将0-9这10个int类型值入队,然后打印一个释放一个,可以自己操作一下。
队列的基本概念就这些,想知道更详细可以去网上搜。
接下来说主题BFS,举个例子,一个迷宫,从起点出发有三条路线通往终点,BFS的大概方式就是三条路线同时走,当其中一条先到达终点时则该条为最短路径,同时走的特点及为BFS的一个特性“宽度搜索”,不需要一条一条走,最后再去比较走的步数,宽度搜索能够较快的找出最优解,我拿一个我第一个写的有关于BFS的题目吧,同为新手的刚了解BFS的也可以去试一试,是一道BFS裸题,很适合熟悉BFS概念:
Knight Moves骑士的移动
A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy. Of course you know that it is vice versa. So you offer him to write a program that solves the ”difficult” part. Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
Input
The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a..h) representing the column and a digit (1..8) representing the row on the chessboard.
Output
For each test case, print one line saying ‘To get from xx to yy takes n knight moves.’
Sample Input
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
Sample Output
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.
题意:意思就是国际棋盘上骑士从一个点到另外一个点的最短移动距离,按照国际象棋的规定移动(在一个3*2的格子里照对角线移动),棋盘规格为8*8.(如果不了解去搜国际象棋棋盘和骑士的移动规则)
解题思路:用BFS层层递进,直到走到终点为止,注意判断移动是否脱离棋盘,和记录走过的坐标。
解题代码:
#include<bits/stdc++.h> using namespace std; int y_d[8][2]={-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1}; //骑士移动规则 int q_p[10][10],step,endx,endy;//记录点 char st1[5],st2[5];//起点终点 struct node{ int x,y,step; //可把该结构体看做每一次移动的记录点 }; int check(int x,int y) //检查移动是否越界 { if(x<0||y<0||x>=8||y>=8||q_p[x][y])return 1; return 0; } int bfs() { queue<node> Q; //注意,队列可以插入结构体 node start,next,end; //起点;下一步;到达后的点 start.x=st1[0]-'a';start.y=st1[1]-'1'; //把输入的起点存入相应结构体
start.step=0; //初始化步数 endx=st2[0]-'a';endy=st2[1]-'1'; //终点,同上 memset(q_p,0,sizeof(q_p)); //把棋盘数组归0 q_p[start.x][start.y]=1; //将起点记录移动过的点的意思 Q.push(start); //起点结构体入队 while(!Q.empty()){ //在while循环中循环直到走到终点 返回相应值 end = Q.front(); //访问队列中第一个元素并用一个变量记录 Q.pop(); //弹出队列第一个元素 if(end.x==endx&&end.y==endy) //这一条是判断起点是否就是终点的 return end.step; for(int i=0;i<8;i++) //该for循环则为BFS的宽度搜索概念的实体化了,层层搜索 { next.x=end.x+y_d[i][0];next.y=end.y+y_d[i][1]; if(next.x==endx&&next.y==endy) return end.step+1; if(check(next.x,next.y))//判断是否越界 continue; next.step = end.step+1;q_p[next.x][next.y]=1; Q.push(next); //将下一步的移动的点入队 } } return 0; } int main (int argc,const char * argv[]) { while(~scanf("%s %s",st1,st2)){ int a=bfs(); printf("To get from %s to %s takes %d knight moves.\n",st1,st2,a); } return 0; }
学习经历少的第一次了解BFS看懂这个可能比较难(大佬除外),但勤能补拙嘛,我也不过看了一晚上才搞懂这个的(手动滑稽),不过不急,慢慢来,先为下一次学习订个目标:熟练使用BFS,了解DFS。