K - 迷宫问题

Description

定义一个二维数组:

int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

Sample Output

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

在实现保存路径的时候没有太好的方法,用了一个数组来存每个坐标的前驱,最后从终点开始向前推,并将路径逆向存入一个数组,最后输出,还要补上(4,4)
其实可以用一个栈来保存的,从终点开始压入栈,最后再依次出栈。

#include<stdio.h>
#include<queue>
#include<string.h>
#include<utility>
using namespace std;
const int inf=0x3f3f3f3f;

int m[5][5];//迷宫 
int d[5][5];//距离 

typedef pair<int,int> P;
queue<P> q;//储存坐标 
P arr[5][5];//用来保存每个坐标的前驱 

int a[4]={-1,1,0,0};//移动 
int b[4]={0,0,-1,1};

void bfs(int x,int y)
{
	q.push(P(x,y));//起点 
	d[x][y]=0;//起点到起点距离 
	int dx,dy;//移动后的坐标 
	while(q.size())//当队列取完后结束 
	{ 
		pair<int,int> p=q.front(); q.pop();//取队列中的坐标 
		if(p.first==4&&p.second==4)//到达终点,结束,返回到终点的距离 
			break;
		for(int i=0;i<5;i++)//遍历出达到的坐标 
		{
			dx=p.first+a[i];//在上一个坐标的基础上改变 
			dy=p.second+b[i];
			if(dx>=0&&dx<5&&dy>=0&&dy<5&&m[dx][dy]==0&&d[dx][dy]==inf)
			{
				q.push(P(dx,dy));//将能到达的坐标放入队列 
				d[dx][dy]=d[p.first][p.second]+1;
				arr[dx][dy]=p;
			}
		}
	}
}
int main()
{
	arr[0][0]=make_pair(0,0);
	memset(d,inf,sizeof(d));//初始化为无穷大 
	for(int i=0;i<5;i++)
		for(int j=0;j<5;j++)
			scanf("%d",&m[i][j]);
	bfs(0,0);
	P arr2[100];//翻转arr,得到arr2 
	int a=4,b=4;
	for(int i=d[4][4]-1;i>=0;i--)
	{
		arr2[i]=arr[a][b];
		a=arr2[i].first;
		b=arr2[i].second;
	}
	for(int i=0;i<d[4][4];i++)
		printf("(%d, %d)\n",arr2[i].first,arr2[i].second);
	printf("(4, 4)\n"); 
	return 0;
}

因为上面那个方法不太好,又重新写了一个用栈来实现的做法。
一开始因为没有把起点压入队列而是压入了栈,导致了错误,汗。。。
还有定义了bfs()函数忘了去使用。。。
最后用栈的时候终止条件是到达了(0,0),我们上一步的pre就是(0,0),已经被压入栈了。

#include<stdio.h>
#include<iostream>
#include<stack>
#include<queue>
#include<string.h>
using namespace std;
typedef pair<int,int> p;
p a;
queue<p> q;
stack<p> s;

int m[5][5];
bool vis[5][5];
p pre[5][5];
int h[]={1,-1,0,0};
int l[]={0,0,1,-1};

void bfs()
{
	q.push(p(0,0));
	vis[0][0]=1;
	while(q.size())
	{
		a=q.front();q.pop();
		for(int i=0;i<4;i++)
		{
			int nx=a.first+h[i];
			int ny=a.second+l[i];
			if(nx>=0&&nx<=4&&ny>=0&&ny<=4&&vis[nx][ny]==0&&m[nx][ny]==0)
			{
				q.push(p(nx,ny));
				vis[nx][ny]=1;
				pre[nx][ny]=p(a.first,a.second);
			}
		}
	}
}
int main()
{
	for(int i=0;i<5;i++)
		for(int j=0;j<5;j++)
			scanf("%d",&m[i][j]);
	memset(vis,0,sizeof vis);
	bfs(); 
	int x=4,y=4;
	s.push(p(4,4));
	while(x!=0||y!=0)
	{
		a=pre[x][y];
		s.push(p(a));
		x=a.first;
		y=a.second;
	}
	while(s.size())
	{
		a=s.top();s.pop();
		printf("(%d, %d)\n",a.first,a.second);
	}
	return 0;
}

第二次做的代码

这次错的也很离谱,bfs()中忘了压入队列

#include<stdio.h>
#include<queue>
#include<stack>
using namespace std;

typedef pair<int,int> p;
p a;
queue<p> q;
int m[5][5];
bool vis[5][5];
p pre[5][5];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
stack<p> s;

void bfs()
{
	q.push(p(0,0));
	while(q.size())
	{
		a=q.front();q.pop();
		if(a.first==4&&a.second==4)
			break;
		for(int i=0;i<4;i++)
		{
			int nx=a.first+dx[i];
			int ny=a.second+dy[i];
			if(nx>=0&&nx<5&&ny>=0&&ny<5&&m[nx][ny]==0&&vis[nx][ny]==0)
			{
				q.push(p(nx,ny));
				vis[nx][ny]=1;
				pre[nx][ny]=p(a.first,a.second);
			}
		}
	}
}
int main(void)
{
	for(int i=0;i<5;i++)
		for(int j=0;j<5;j++)
			scanf("%d",&m[i][j]);
	bfs();
	s.push(p(4,4));
	p b=pre[4][4]; 
	while(b.first!=0||b.second!=0)
	{
		s.push(b);
		b=pre[b.first][b.second];
	}
	s.push(p(0,0));
	while(s.size())
	{
		b=s.top();s.pop();
		printf("(%d, %d)\n",b.first,b.second);
	}
	return 0;
}

目前我会的最简单的解法
dfs,设置一个变量flag,当走到终点后将flag设为1,如果flag是1,后面所有的递归调用都立即返回
如果没有这一步,后面的操作会对数组里的内容进行修改

或者,直接用vis来记录哪里走过了,最后直接循环遍历即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int ma[10][10];
typedef pair<int, int> P;
P arr[10];
bool vis[10][10], flag;
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};

void dfs(int x, int y, int state)
{
	if (x == 4 && y == 4) {
		printf("(0, 0)\n");
		for (int i = 0; i < 8; i++) {
			printf("(%d, %d)\n", arr[i]);
		}
		flag = 1;
		return;
	}
	for (int i = 0; i < 4; i++) {
		// 当走到终点后,立即返回,否则后面的操作会对数组造成修改 
		if (flag == 1) {
			return;
		}
		int nx = x + dx[i], ny = y + dy[i];
		if (nx >= 0 && nx < 5 && ny >= 0 && ny < 5 && vis[nx][ny] == 0 && ma[nx][ny] == 0) {
			vis[nx][ny] = 1;
			arr[state] = P(nx, ny);
			dfs(nx, ny, state + 1);
			vis[nx][ny] = 0;
		}
	}
}

int main(void)
{
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cin >> ma[i][j];
		}
	}
	vis[0][0] = 1;
	dfs(0, 0, 0);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值