SCAU 魔改迷宫问题

18276 走迷宫(传送门)

Description

有一个N*M的格子迷宫,1代表该格子为墙,不能通过,0代表可以通过,另外,在迷宫中
有一些传送门,走到传送门的入口即会自动被传送到传送门的出口(一次传送算1步)。人在迷宫中可以尝试
上下左右四个方向移动。现在给定一个迷宫和所有传送门的出入口,以及起点和终点,
问最少多少步可以走出迷宫。如果不能走出迷宫输出“die”。

输入格式

该程序为多CASE,第1行为CASE的数量
每一个CASE,第1行为两个数N(行)和M(列)
然后N行每行M个数
之后是一个数W,为传送门的数量
之后每行一个传送门的入口坐标c1(行),r1(列)和出口坐标c2,r2
之后是起点坐标和终点坐标sc(行) sr(列) ec(行) er(列)

注:传送门出入口和起点坐标和终点坐标不会出现在墙的位置
所有数字不超过100

输出格式

如题

 

输入样例

2
4 3
011
011
110
110
1
1 0 2 2
0 0 3 2
2 2
01
10
0
0 0 1 1

 

输出样例

3
die

思路:

走迷宫是金典bfs问题了,这里简单概述下。

在迷宫中的每一步起点now,我们有4个方向可以选择到达终点next,在4个方向中,我们需要选择不越界,不是墙,未走过的合法路径,作为我们下一次的起点now。我们使用一个队列来维护now和next的交替,直到队列为空,说明迷宫每一条路径全部遍历。每走一步,我们然step+1实现记录步数。

这道题只是在原有基础上做出了一点点改变,多出了第五个方向即传送门。当我们遇到传送门时,我们就无法选择四个方向。next就是传送门的出口。

我们把迷宫的最外一圈设为墙,将越界条件和墙的条件合并判断。

代码:

#include<iostream>
using namespace std;
#include<algorithm>
#include<queue>
int dex_x[4] = {-1,0,1,0};
int dex_y[4] = {0,1,0,-1};
char map[102][102];
struct node {
	int x;
	int y;
	int step;
};
node door[102][102];
int main() {
	ios::sync_with_stdio(false);
	int T; cin >> T;
	for (int i = 0; i < 102;i++) {
		for (int j = 0; j < 102;j++) {
			map[i][j] = '1';
		}
	}
	for (int i = 0; i < T;i++) {
		int N, M; cin >> N >> M;
		for (int i = 1; i <= N;i++) {
			for (int j = 1; j <= M;j++) {
				cin >> map[i][j];
			}
		}
		int w; cin >> w;
		for (int i = 0; i < w;i++) {
			node c1, c2;
			cin >> c1.x >> c1.y >> c2.x >> c2.y;
			++c1.x; ++c1.y; ++c2.x; ++c2.y;
			door[c1.x][c1.y] = c2;
			map[c1.x][c1.y] = '2';//传送们我们设为‘2’
		}
		int sc, sr, ec, er;
		cin >> sc >> sr >> ec >> er;
		++sc; ++sr; ++ec; ++er;
		//初始化结束,
		queue<node>q;
		node start; start.x = sc; start.y = sr, start.step = 0;
		q.push(start);
		while (!q.empty()) {
			node now, next;
			now = q.front();
			if (now.x == ec && now.y == er) {  break; }//先判断,如果队首时终点则直接结束,保留队首。
			q.pop();
			if (map[now.x][now.y] == '2') {
				next = door[now.x][now.y];
				next.step = now.step + 1;
				q.push(next);
				map[now.x][now.y] = '1';
				map[next.x][next.y] = '1';//标记已访问过
			}
			else {
				for (int i = 0; i < 4;i++) {
					next.x = now.x + dex_x[i];
					next.y = now.y + dex_y[i];
					if (map[next.x][next.y]!='1') {
						next.step = now.step + 1;
						q.push(next);
						if(map[next.x][next.y]!='2')map[next.x][next.y] = '1';//除了传送门,标记已访问过
					}
				}
			
			}
			
		}
		if (q.empty())cout << "die" << endl;//队空则说明未找到终点
		else {
			node end = q.front();
			cout << end.step << endl;
		}
	}

}

18440 走迷宫(边界传送)

Description

有一个N*M(N,M<=10)的格子迷宫,1代表该格子为墙,不能通过,0代表可以通过,人在迷宫中可以尝试上下左右四个方向移动。
另外,在迷宫中如果从左边走出迷宫会回到迷宫最右边一格(只要该格不是墙),行不变,同样,从右边走出迷宫会
回到迷宫最左边一格,向上走出迷宫会回到迷宫最下边一格,向下走出迷宫会回到迷宫最上边一格。
现在给定一个迷宫,以及起点和终点,问最少多少步可以走出迷宫。如果不能走出迷宫输出“die”。

输入格式

该程序为多CASE,第1行为CASE的数量
每一个CASE,第1行为两个数N(行)和M(列)
然后N行每行M个数,之后是起点坐标和终点坐标sc(行) sr(列) ec(行) er(列)

输出格式

如题

输入样例

2
4 3
011
010
110
110
0 0 3 2
2 2
01
10
0 0 1 1

输出样例

4
die

 思路:

这题和上一题差不多,在最基础的迷宫问题上做了一些变化。当next为边界时,next值会变化,变化规律也比较容易。实际上,每处理完一个case,应该再初始化map,只是不知道为什么就过了。

#include<iostream>
using namespace std;
#include<algorithm>
#include<queue>
int dex_x[4] = {-1,0,1,0};
int dex_y[4] = {0,1,0,-1};
char map[102][102];
struct node {
	int x;
	int y;
	int step;
};
int main() {
	ios::sync_with_stdio(false);
	int T; cin >> T;
	for (int i = 0; i < 102; i++) {
		for (int j = 0; j < 102; j++) {
			map[i][j] = '2';
		}
	}
	for (int i = 0; i < T; i++) {
		int N, M; cin >> N >> M;
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				cin >> map[i][j];
			}
		}
		node start, end;
		cin >> start.x >> start.y >> end.x >> end.y;
		++start.x; ++start.y; ++end.x; ++end.y;
		queue<node>q;
		start.step = 0;
		q.push(start);
		while (!q.empty()) {
			node now, next;
			now = q.front();
			if (now.x == end.x && now.y == end.y)break;
			q.pop();
			for (int i = 0; i < 4; i++) {
				next.x = now.x + dex_x[i];
				next.y = now.y + dex_y[i];
				if (map[next.x][next.y] == '2') {//变换坐标
					if (dex_x[i] == 0 && dex_y[i] == -1) { next.y = M; }
					else if (dex_x[i] == 0 && dex_y[i] == 1) { next.y = 1; }
					else if (dex_y[i] == 0 && dex_x[i] == 1) { next.x = 1; }
					else { next.x = N; }
				}
				if (map[next.x][next.y]=='0') {
					next.step = now.step + 1;
					q.push(next);
					map[next.x][next.y] = '1';
				}
			}
		}
		if (q.empty())cout << "die" << endl;
		else cout << q.front().step << endl;
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值