迷宫问题 -- BFS 和 DFS 实现

题目:

给你一个 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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值