NOJ 木乃伊迷宫代码和思路

这篇博客详细介绍了如何利用广度优先遍历(BFS)解决一个分支限界问题,即在一个只有右侧和下方有墙的迷宫中,人和木乃伊同时移动。文章探讨了处理墙的规则、移动步数的计算、防止重复路径的visit数组以及判断行走方向的函数等关键点。通过输入迷宫信息、设定初始位置和目标位置,利用BFS判断人是否能到达出口而不被木乃伊追上。

这道题是分支限界的方法,工具是BFS(广度优先遍历),下面列举了我觉得有问题的几个点(如果有补充或者还有其他问题,请私信,或者评论):
1.墙的问题:这道题每个格子只有右边和下边有墙,但是注意一点,如果一个格子的左边的格子有了墙,那么这个格子也就相当于左边有了墙,所以在读入墙的时候,我们要注意一点:一个格子的左边有墙,那么它右边的格子的左边也就要加上一堵墙,但是这个加墙的前提是右边有墙的格子不是最右边的格子,加在格子下面的墙是同理的

2.这里的走步数的话,设置一个二维数组来保存人走的方向,木乃伊的话一定要在列上走到人所在的那一列,如果碰到墙的话,就一直在那个格子不动!!!走到人的那一列之后才开始在x方向或者说列方向上运动。这里木乃伊追赶的是人在走一步之后的位置。

3.这里要记得设置个visit数组,这样来判重,防止一样的情况多次出现,从而人没有办法走到出口,而一直在迷宫中转圈圈

4.可以写个函数来判断现在这个方向是不是可以走,传过去的形参是当前结点和我们选择的方向,然后在函数中设置一个next结点,通过next结点来保存下一个进入队列的结点的状态,并通过next中的bool类型的变量来保存这个结点是否可以进入队列。如果函数返回结点中这个bool型变量的值是false(有三种情况会false:一是人或者木乃伊越界了——超过了迷宫的边界;二是人被木乃伊追到了——木乃伊追到人是指在人已经动了之后在追的,而不是追先前的人的状态或者说不是我们传过来的那个结点所在的位置;三是遇到了墙,人在这个方向走不通),说明不能进入队列。
代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

struct Node {
	int now_xr, now_yr;
	int now_xm, now_ym;
	bool useful;
};

int visit[6][6][6][6];//保存状态
int a[6][6][4];//对应每个方格是否有墙,以及墙在哪个方向
//0代表右方,1代表左方,2代表下方,3代表上方 
int wish_x, wish_y;
int d[4][2] = { {0,1}/*向右走*/,{0,-1}/*向左走*/,{1,0}/*向下走*/,{-1,0}/*向上走*/ };

queue<Node> map_1;

void input() {//读入
	int n;
	cin >> n;
	int x, y, dir;
	for (int i = 0; i < n; i++) {
		if (dir == 0) {
			a[x][y][2] = 1;
			if (x < 5) {//没有比最右边的格子更加右边的格子
				a[x ][y][3] = 1;
			}
		}
		else {
			a[x][y][0] = 1;
			if(y<5){//x==5 已经是最下面了
				a[x][y][1] = 1;
			}
		}
	}
	Node now;
	cin >> now.now_xm >> now.now_ym >> now.now_xr >> now.now_yr;
	cin >> wish_x >> wish_y;
	map_1.push(now);
}

bool iswall(int x, int y, int i) {//判断是不是撞到墙
	switch (i) {
	case 0://向右走
		return a[x][y][0];

	case 1://向左走
		return a[x][y][1];

	case 2://向下走
		return a[x][y][2];

	case 3://向上走
		return a[x][y][3];
	}
	return -1;//代表传过来的i值错误
}

Node decide(Node now, int i) {
	//判断是否撞到了墙以及是否越界
	Node next;
	next.now_xr = now.now_xr + d[i][0], next.now_yr = now.now_yr + d[i][1];
	if ((next.now_xr < 0 || next.now_xr >= 6 || next.now_yr < 0 || next.now_yr >= 6) || iswall(now.now_xr, now.now_yr, i)) {
		next.useful = false;
		return next;
	}
	next.now_xm = now.now_xm;
	next.now_ym = now.now_ym;
	int res = 2;
	//先到同一列 
	while (res--) {
		if (next.now_ym < next.now_yr && !iswall(next.now_xm, next.now_ym, 0)) {
			next.now_ym++;
		}
		else if (next.now_ym > next.now_yr && !iswall(next.now_xm, next.now_ym, 1)) {
			next.now_ym--;
		}
		else if (next.now_ym == next.now_yr) {
			if (next.now_xm < next.now_xr && !iswall(next.now_xm, next.now_ym, 2)) {
				next.now_xm++;
			}
			else if (next.now_xm > next.now_xr && !iswall(next.now_xm, next.now_ym, 3)) {
				next.now_xm--;
			}
			if (next.now_xm == next.now_xr && next.now_ym == next.now_yr) {
				next.useful = false;
				return next;
			}
		}
	}
	/*if (visit[next.now_xr][next.now_yr][next.now_xm][next.now_ym]) {
		next.useful = false;//前面访问过的点不再入队
	}
	else {
		visit[next.now_xr][next.now_yr][next.now_xm][next.now_ym] = 1;
		next.useful = true;
	}
	return next;*/
	next.useful = true;
	return next;
}

bool bfs() {
	Node now;
	while (!map_1.empty()) {
		now = map_1.front();
		map_1.pop();

		if (visit[now.now_xr][now.now_yr][now.now_xm][now.now_ym]) {
			continue;
		}
		visit[now.now_xr][now.now_yr][now.now_xm][now.now_ym] = 1;
		Node next;
		for (int i = 0; i < 4; i++) {
			next = decide(now, i);
			if (next.useful) {
				if (next.now_xr == wish_x && next.now_yr == wish_y) {//到了出口的地方
					return true;
				}
				else map_1.push(next);//没有走到人的位置,入队,同时也说明了木乃伊没有走到人的位置 
			}
		}
	}
	return false;
}

int main() {
	
	input();

	if (bfs())
	{
		cout << "Yes" << endl;
	}
	else
	{
		cout << "No" << endl;
	}
	return 0;
}
### NOJ 平台电子老鼠闯迷宫解题思路 针对NOJ 1042中的电子老鼠闯迷宫问题,该问题是典型的最短路径寻找问题。由于地图固定且只有上下左右四个方向可以移动,广度优先搜索(BFS)成为解决此类问题的理想选择[^1]。 BFS是一种逐层向外扩展的遍历方式,非常适合用于无权图上的最短路径计算。具体应用在此处意味着从起点出发,逐步探索每一个可达节点直到找到目标位置为止。为了防止重复访问已经到达过的地点以及记录当前所走步数,通常还需要额外的数据结构来辅助完成这一过程。 #### 数据准备阶段 输入数据包含了迷宫尺寸、起始坐标(S),终止坐标(T),以及由一系列整数组成的地图布局信息。其中,“1”代表不可通行区域(障碍物/墙壁),而“0”则标记可自由通过的道路。因此,在实际编码之前,先解析这些原始数据并构建出适合处理的形式是非常必要的。 ```python from collections import deque def parse_input(): n = int(input()) # 迷宫大小 sx, sy, ex, ey = map(int, input().split()) maze = [] for _ in range(n): row = list(map(int, input().split())) maze.append(row) return n, (sx-1, sy-1), (ex-1, ey-1), maze ``` #### 主体逻辑设计 基于上述分析,下面给出完整的Python版本解决方案: ```python def bfs(maze, start, end): directions = [(0,-1),(0,1),(-1,0),(1,0)] # 定义四种可能的方向 queue = deque([(start[0], start[1], 0)]) # 初始化队列,加入初始状态(x,y,distance) visited = set() # 记录已访问的位置集合 while queue: x, y, dist = queue.popleft() if (x, y) == end: # 如果当前位置等于终点,则返回距离 return dist for dx, dy in directions: # 尝试向四周扩散 nx, ny = x + dx, y + dy if not (0 <= nx < len(maze)) or \ not (0 <= ny < len(maze)): # 越界判断 continue elif maze[nx][ny] != 0 or ((nx, ny) in visited): # 阻碍物或已被访问过的情况 continue else: visited.add((nx, ny)) queue.append((nx, ny, dist+1)) if __name__ == "__main__": N, S, E, M = parse_input() result = bfs(M, S, E) print(result) ``` 这段程序首先定义了一个`bfs()`函数用来执行具体的广搜操作;接着实现了简单的命令行交互接口读取测试案例,并调用此方法获取最终结果输出。注意这里假设所有输入均合法有效,即不存在非法字符等问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小编程员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值