#include<iostream>#include<queue>usingnamespace std;constint N =100+10;typedef pair<int,int> PII;int dx[4]={-1,0,1,0}, dy[4]={0,1,0,-1};int g[N][N], d[N][N];
queue<PII> q;int res, n, m;intbfs(int x,int y){
d[x][y]=0;
g[x][y]=1;
q.push({x, y});
PII end ={n -1, m -1};while(q.size()){auto u = q.front(); q.pop();int dis = d[u.first][u.second];if(u == end)return dis;for(int i =0; i <4; i ++){int a = u.first + dx[i], b = u.second + dy[i];if(a <0|| a == n || b <0|| b == m)continue;if(g[a][b])continue;
g[a][b]=1;
d[a][b]= dis +1;
q.push({a, b});}}}intmain(){
cin >> n >> m;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++)
cin >> g[i][j];
cout <<bfs(0,0)<< endl;return0;}
(2)打印最短路径——在bfs函数的基础上多了一个print函数
a. 思想
b. 代码
#include<iostream>#include<queue>usingnamespace std;constint N =100+10;int g[N][N];int dx[4]={-1,0,1,0}, dy[4]={0,1,0,-1};typedef pair<int,int> PII;
PII pre[N][N];// 往队列中添加探测灯照到的元素
queue<PII> q;int n, m;voidbfs(int x,int y){// 一开始点在(0,0)上,将(0,0)点作标记并加入队列
g[x][y]=1;
q.push({x, y});while(q.size()){// 取队头,将队头出队
PII f = q.front();
q.pop();// 在队头这个点上打探照灯,照到周围四个点,顺序为上右下左for(int i =0; i <4; i ++){// 照到的点坐标为(a,b)int a = f.first + dx[i], b = f.second + dy[i];// 如果照到的点的横坐标或纵坐标越界就跳过该点if(a <0|| a == n || b <0|| b == m)continue;// 如果照到的这个点有障碍物或者走过就跳过该点if(g[a][b])continue;// 如果照到的点没越界并且没走过或没障碍物,就将照到的点作标记
g[a][b]=1;// 记录照到的点的前驱
pre[a][b]= f;// 将照到的点入队
q.push({a, b});}}}// 找到最短路径voidprint(int x,int y){// 递归到(0,0)这个点了if(!x &&!y){
cout << x <<" "<< y << endl;return;}auto c = pre[x][y];print(c.first, c.second);
cout << x <<" "<< y << endl;}intmain(){
cin >> n >> m;for(int i =0; i < n ; i ++)for(int j =0; j < m; j ++)
cin >> g[i][j];// 先用bfs将迷宫上所有点遍历一遍 bfs(0,0);// 再将终点的下标(4,4)传入print函数,打印最短路径print(n -1, m -1);return0;}
4. 八数码问题——bfs函数
#include<iostream>#include<queue>#include<unordered_map>usingnamespace std;// 往队列里加的是扩展出的新布局
queue<string> q;int dx[4]={-1,0,1,0}, dy[4]={0,1,0,-1};// 放键值对,键是布局,值是从初始布局变化到该布局x移动了多少次
unordered_map<string,int> d;// 传入初始布局intbfs(string init){// 代表从初始布局变到初始布局x移动0次
d[init]=0;// 将初始布局加入队列
q.push(init);// 定义最终布局
string end ="12345678x";while(q.size()){// 取出队头布局
string u = q.front(); q.pop();// dis代表从初始布局变化到队头布局,x移动了多少次int dis = d[u];// 如果取出的队头布局是最终布局,那么输出变化到最终布局时x的移动次数if(u == end)return d[u];// 求出x在二维布局中的下标; 也就是先求出x在一维字符串中的下标,再求出x在二维布局中的下标int k = u.find('x');int x = k /3, y = k %3;// 探射灯照到x周围4个点,尝试将x与周围点交换for(int i =0; i <4; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a ==3|| b <0|| b ==3)continue;// 若探射灯照到的这个点没有越界,就交换x和该点,注意是在字符串中交换着两个字符swap(u[k], u[3* a + b]);// 如果交换后的新布局不在map中,代表这个新布局之前没有出现过,那么就在map中加入新布局,并往队列中加入这个新布局if(!d.count(u)) d[u]= dis +1, q.push(u);// 还原回队头布局,x继续交换下一个照到的点,再得到新布局swap(u[k], u[3* a + b]);}}// 无法从初始布局变化到最终布局,那么就不存在解决方案return-1;}intmain(){// init代表初始布局
string init;char c;for(int i =0; i <9; i ++) cin >> c, init += c;
cout <<bfs(init)<< endl;return0;}