4.8记录 迷宫问题

该博客介绍了如何使用深度优先搜索(DFS)和广度优先搜索(BFS)解决包含0和-1的迷宫路径问题,并给出了C++实现代码。在进阶问题中,针对输出所有路线方案的需求,采用了DFS进行全排列操作。文章还包含了两种搜索算法的适用性和优缺点分析。
摘要由CSDN通过智能技术生成

题目:给定一个含0和-1的迷宫,其中0可以通过而-1不能。输出任意一种路径。
这题有DFS和BFS两种方式。
DFS很容易:如果回溯了,则一定是遇到了死路,那么之前回溯过的部分都可以被覆盖掉,而且同一步只会走到唯一的坐标上(否则一定回溯了),因此只要开一个res[i]数组表示第i步到达的坐标就可以了。
BFS一步会走至多4个点,因此我们可以参考链式前向星的存图方式,用一个数组pre[i][j]表示到达点(i,j)的点(到达某点的点是唯一的)。这样我们再递归的输出就可以了。
代码如下(附赠样例一组):

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<utility>
using namespace std;
typedef pair<int,int> pr;
queue<pr> Q;
struct yjx{
	int x,y;
}res[100001],pre[1001][1001];
bool lipu = 1;
int n,m,judge[1001][1001],s[1001][1001],dx[] = {0,1,0,-1},dy[] = {1,0,-1,0};
void dfs(int nx,int ny,int ex,int ey,int cnt){
	int i;
	if(nx == ex && ny == ey){
		res[cnt].x = ex,res[cnt].y = ey;
		for(i = 1;i <= cnt;i++){
			if(i != 1) printf("->");
			//if(i % 5 == 1 && i != 1) printf("\n");
			printf("(%d,%d)",res[i].x,res[i].y);
			lipu = 0;
			printf("\n");
		}
		return;
	}
	if(s[nx][ny] || judge[nx][ny]) return;
	judge[nx][ny] = 1;
	res[cnt].x = nx,res[cnt].y = ny;
	if(nx < n) dfs(nx + 1,ny,ex,ey,cnt + 1);
	if(ny < m) dfs(nx,ny + 1,ex,ey,cnt + 1);
	if(nx > 1) dfs(nx - 1,ny,ex,ey,cnt + 1);
	if(ny > 1) dfs(nx,ny - 1,ex,ey,cnt + 1);
}
void goodbye(int a,int b,int c,int d){
	if(pre[a][b].x) goodbye(pre[a][b].x,pre[a][b].y,c,d);
	printf("(%d,%d)",a,b);
	if(a != c || b != d) printf("->");
	lipu = 0;
}
void bfs(int nx,int ny,int ex,int ey,int cnt){
	int i,x1,y1;
	Q.push(make_pair(nx,ny));
	judge[nx][ny] = 1;
	while(!Q.empty()){
		nx = Q.front().first,ny = Q.front().second;
		if(nx == ex && ny == ey) goodbye(nx,ny,ex,ey);
		Q.pop();
		for(i = 0;i <= 3;i++){
			x1 = nx + dx[i],y1 = ny + dy[i];
			if(x1 >= 1 && x1 <= n && y1 >= 1 && y1 <= m && s[x1][y1] && !judge[x1][y1]){
				Q.push(make_pair(x1,y1));
				judge[x1][y1] = 1;
				pre[x1][y1].x = nx,pre[x1][y1].y = ny;
			}
		}
	}
}
int main(){
	char ch[4];
	int i,j,temp,nx,ny,ex,ey;
	scanf("%d %d",&n,&m);
	for(i = 1;i <= n;i++){
		for(j = 1;j <= m;j++){
			scanf("%d",&temp);
			s[i][j] = temp;
		}
	}
	scanf("%d %d %d %d",&nx,&ny,&ex,&ey);
	/*scanf("%s",ch);
	if(ch[0] == 'd' || ch[0] == 'D') dfs(nx,ny,ex,ey,1);
	else{
		if(ch[0] == 'b' || ch[0] == 'B') bfs(nx,ny,ex,ey,1);
		else printf("???");
	}*/
	if(lipu) printf("no way");
	return 0;
}
/*
5 9
0 -1 0 0 0 0 0 0 -1
0 0 0 0 -1 0 0 0 -1
-1 0 0 0 0 0 -1 -1 -1
0 0 -1 -1 0 0 0 0 0
0 0 0 0 0 0 0 -1 -1
1 1 4 9
*/

进阶问题:(洛谷P1328)输出所有的路线方案。
根据上一道题的分析,这个就很难再用BFS了,加上数据范围也不大,我们就直接DFS好了。
对于已经走过的,我们只用在目前判断不可通过就行了,路线之间无影响,因此我们大可以模仿全排列操作。
代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<utility>
using namespace std;
typedef pair<int,int> pr;
queue<pr> Q;
struct yjx{
	int x,y;
}res[100001];
bool lipu = 1;
int n,m,judge[1001][1001],s[1001][1001],dx[] = {0,-1,0,1},dy[] = {-1,0,1,0};
void dfs(int nx,int ny,int ex,int ey,int cnt){
	int i,x1,y1;
	if(nx == ex && ny == ey){
		for(i = 0;i < cnt;i++){
			if(i) printf("->");
			printf("(%d,%d)",res[i].x,res[i].y);
			lipu = 0;
		}
		printf("\n");
		return;
	}
	for(i = 0;i <= 3;i++){
		x1 = nx + dx[i],y1 = ny + dy[i];
		if(x1 > 0 && x1 <= n && y1 > 0 && y1 <= m && !judge[x1][y1] && s[x1][y1]){
			judge[x1][y1] = 1;
			res[cnt].x = x1,res[cnt].y = y1;
			dfs(x1,y1,ex,ey,cnt + 1);
			judge[x1][y1] = 0;
		}
	}
}
int main(){
	int i,j,nx,ny,ex,ey;
	scanf("%d %d",&n,&m);
	for(i = 1;i <= n;i++){
		for(j = 1;j <= m;j++){
			scanf("%d",&s[i][j]);
		}
	}
	scanf("%d %d %d %d",&nx,&ny,&ex,&ey);
	res[0].x = nx,res[0].y = ny;
	judge[nx][ny] = 1;
	dfs(nx,ny,ex,ey,1);
	if(lipu) printf("-1");
	return 0;
}

(注:洛谷对这题的走法规定了优先级,我只是做一个提醒,具体顺序怎么操作,请读者自行研究)
Thank you for reading!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值