题目:
给你一个 n 行 m 列的二维迷宫。'S'表示起点,'T' 表示终点,'#' 表示墙壁,'.' 表示平地。你需要从 'S' 出发走到 'T',每次只能上下左右走动,并且不能走出地图的范围以及不能走到墙壁上。请你计算出走到终点需要走的最少步数。
输入格式第一行输入 n, m 表示迷宫大小。(1≤n,m≤100)
接下来输入 n 行字符串表示迷宫,每个字符串长度为 m。(地图保证有且仅有一个终点,一个起始点)输出格式输出走到终点的最少步数,如果不能走到终点输出 −1,占一行。
输入:
9 9
S.#......
..#.###..
..#.#...#
....#..#.
..##..#..
.#...#...
#...#....
...#.....
........D
输出
32
思路:BFS -- 类似于树的层次遍历 - 用队列实现,每次对顶元素出队,对顶元素相连的元素进队(需满足数组下标未越界 且 此位置未访问 且 不是墙)
需要3个矩阵(二维数组):
maze[ ][ ] -- 存储迷宫信息
mark[ ][ ] -- mark[ i ][ j ] = 1表示 i,j位置已访问,初试值全零
step_num[ ][ ] -- step_num[ i ][ j ] 中的值表示起点到i,j需要的步数,初试值全零
C++实现代码:
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
int maze[105][105]; //maze存储迷宫
int mark[105][105]; //mark标志当前位置是否已经访问
int step_num[105][105]; //step_num[i][j] 表示起点走到i,j的位置需要的步数
int cnt=0;
int chx[4]={1,0,-1,0};
int chy[4]={0,1,0,-1};
int n,m; //全局变量
struct point
{
int x;
int y;
point(int xx,int yy) // 初始化方法
{
x=xx;
y=yy;
}
};
int bfs(int i,int j)
{
queue<point>q;
q.push(point(i,j));
mark[i][j]=1; //标记起点已访问
while(!q.empty()) //队列非空时循环
{
i=q.front().x;
j=q.front().y;
q.pop(); //队首元素出队
for(int k=0;k<4;k++) //访问队首位置x,y的上下左右四个元素
{
int tx=i+chx[k];
int ty=j+chy[k];
if( 0<=tx<n && 0<=ty<m && !mark[tx][ty] && (maze[tx][ty]=='.' || maze[tx][ty]=='D')) //下标未越界 且 未访问 且 不是墙
{
step_num[tx][ty]=step_num[i][j]+1; //用于统计步数:count为当前的步数=上一次的步数+1
mark[tx][ty]=1; //标记已访问
if(maze[tx][ty]=='D')
return 1; //可以遍历到终点, 返回true -- 注意此时全局变量count的值就是记录的从起点到终点需要的步数
else q.push(point(tx,ty)); //tx,ty是迷宫中当前遍历到的位置的下标
}
}
}
return 0; //否则 返回false
}
int main()
{
int sx,sy; // 用于记录起点坐标
int dx,dy; // 用于记录终点坐标
char one_char;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>one_char; //逐个字符读入
if(one_char=='S')
{
sx=i;sy=j; //记录初始点
}
else if(one_char=='D')
{
dx=i;dy=j; //记录初始点
}
maze[i][j] = one_char;
}
if(bfs(sx,sy)) printf("%d\n",step_num[dx][dy]);
else printf("-1\n");
return 0;
}
DFS - 判断起点到终点是否有路径相连
输入:
9 9
S.#......
..#.###..
..#.#...#
....#..#.
..##..#..
.#...#...
#...#....
...#.....
........D
输出
Yes
#include<cstdio>
char maze[105][105]; // 存储迷宫
int mark[105][105]; // 标记是否已访问
int xx[] = {1, -1, 0, 0};
int yy[] = {0, 0, 1, -1};
int n, m, t;
int sx, sy, dx, dy; //起点 终点坐标
void dfs(int a, int b)
{
if(mark[dx][dy]!=0) return; // 剪枝 -- 如果已访问,则直接返回
mark[a][b] = 1;
if(maze[a][b]=='D') return; //遍历到终点 -- 直接返回
for(int i=0; i<4; ++i)
{
if( 0<= a+xx[i] <n && 0<= b+yy[i] <m && // 下标未越界
mark[a+xx[i]][b+yy[i]]==0 && // 且 此节点未遍历
( maze[a+xx[i]][b+yy[i]]=='.' || maze[a+xx[i]][b+yy[i]]=='D') ) // 且有通路或者为终点
{
dfs(a+xx[i], b+yy[i]);
}
}
}
int main()
{
scanf("%d%d ", &n, &m); // 后面多个空格,就不用了吸收第一行的换行符了
for(int i=0;i<n;++i)
{
gets(maze[i]); //gets() 接受一个字符串,可以接收空格并输出
for(int j=0;j<m;++j) //找起点和终点
{
if(maze[i][j]=='S')
{
sx = i;
sy = j; //找起点
}
else if(maze[i][j]=='D')
{
dx = i;
dy = j; //找终点
}
}
}
dfs(sx, sy);
// for(int i=0;i<n;++i)
// {
// for(int j=0;j<m;++j) //看一下标记矩阵的样子
// {
// printf("%d", mark[i][j]);
// }
// printf("\n");
// }
printf(mark[dx][dy]!=0 ? "Yes\n" : "No\n");
return 0;
}
POJ3984
BFS:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include<iomanip>
using namespace std;
int maze[6][6]; // 存储迷宫信息-- 矩阵
int vis[6][6];// 标记是否已访问-- 矩阵
struct node
{
int r,c;
};
queue<node> que;
int dx[4] = {0,0,-1,1};
int dy[4] = {-1,1,0,0};
int cnt = 0;
int d[10][10]; // 记录是第几层 -- 矩阵
node father[10][10]; //记录该节点的父节点 -- 矩阵
vector <node> nodes; //记录路径
void printf_ans(node u) //此函数输入node是终点坐标的结构体信息
{
while(1) //反向找要输出的路径
{
nodes.push_back(u);
if (d[u.r][u.c] == 0) break; //头结点
u = father[u.r][u.c]; //找出对应的父节点
}
for (int i = (int)nodes.size() - 1; i >= 0; i--)//反向遍历输出结果
{
printf("(%d, %d)\n",nodes[i].r,nodes[i].c);
}
}
void bfs()
{
node zero;
zero.r = 0;//从 0 0点开始遍历
zero.c = 0;
d[0][0] = 0;
vis[0][0] = 1;
que.push(zero);
while(!que.empty())
{
node front = que.front();
que.pop();
if (front.r == 4 && front.c == 4) //终点 右下角--下标4 4
{
printf_ans(front);
return;
}
for(int i = 0; i < 4; i++)//注意:如果迷宫矩阵全部可达的话,则不同的访问顺序会导致不同的结果出现
{ // x = {0,0,-1,1}; y = {-1,1,0,0}; 这里访问上下左右的顺序会影响结果
int x = front.r + dx[i];
int y = front.c + dy[i];
node v;
v.r = x;
v.c = y;
if (0 <= x < 5 && 0 <= y < 5 && maze[x][y] == 0 && !vis[x][y])
{
d[v.r][v.c] = d[front.r][front.c] + 1;//记录层数
father[v.r][v.c] = front;//记录该节点的父节点
vis[x][y] = 1;
que.push(v);
}
}
}
}
int main()
{
for (int i = 0; i < 5; i++)//读入maze
{
for (int j = 0; j < 5; j++)
{
cin >> maze[i][j];
}
}
bfs();
}
DFS:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<string>
#include<string.h>
#include<queue>
#include<map>
const int INF = 0x3f3f3f3f;
const int NINF = -INF -1;
using namespace std;
int maze[10][10];
bool vis[10][10];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
struct point {
int x, y;
}tmp[100], ans[100]; // 两个结构体数组
int MINN;
void dfs(int x, int y, int cnt) {
tmp[cnt].x = x;// 这里每一次数据的更新 都会把原数据覆盖
tmp[cnt].y = y;
if (x == 4 && y == 4) {
if (cnt < MINN) {
MINN = cnt;
for (int i = 0; i < MINN; i++)
ans[i] = tmp[i];// 这里每一次数据的更新 都会从0开始,把原数据覆盖
}
return;
}
for (int i = 0; i < 4; i++) {
int X = x+dx[i];
int Y = y+dy[i];
if (X < 0 || X > 4 || Y < 0 || Y > 4) continue;
if (!maze[X][Y] && !vis[X][Y]) {
vis[X][Y] = 1;
dfs(X, Y, cnt+1);// 这里每一次数据的更新 都会把原数据覆盖
vis[X][Y] = 0;
}
}
}
int main() {
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
scanf("%d", &maze[i][j]);
memset(vis, 0, sizeof(vis));
MINN = INF;
dfs(0, 0, 0);
for (int i = 0; i < MINN; i++)
printf("(%d, %d)\n", ans[i].x, ans[i].y);
printf("(4, 4)\n");
return 0;
}