Rescue --- bfs 记录

问题描述
天使被 MOLIGPY 抓住了!他被莫利皮关进了监狱。监狱被描述为一个 N * M (N, M <= 200) 矩阵。监狱里有墙、路和守卫。
天使的朋友们想要拯救天使。他们的任务是:接近天使。我们假设“接近天使”是到达天使所在的位置。当网格中有守卫时,我们必须杀死他(或她?)才能进入网格。我们假设我们上下左右移动需要 1 个单位时间,杀死一个守卫也需要 1 个单位时间。而且我们足够强大,可以杀死所有的守卫。
你必须计算接近天使的最短时间。(当然,我们只能向上、向下、向左和向右移动到边界内的相邻网格。)

输入
第一行包含两个整数,分别代表 N 和 M。
然后是 N 行,每行有 M 个字符。“.” 代表道路,“a”代表天使,“r”代表天使的每个朋友。
处理到文件末尾。

输出
对于每个测试用例,您的程序应该输出一个整数,代表所需的最短时间。如果不存在这样的数字,则应输出包含“可怜的天使必须终生待在监狱中”的行。

Sample Input
在这里插入图片描述

Sample Output
13

初始状态: 天使位置(st_x, st_y)
目标状态: 朋友位置mp[x][y] == ‘r’
移动规则:r[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}
利用规则(移动方式) 生成下一层的所有状态节点,并依次放入队列中
层层往下展开,直到到达终点
注:
1)因为朋友有多个,而天使只有一个,所以从天使到朋友,先到的就一定是用时最少的
2)因为需要攻击’x’并且时长+1, 所以里面放入队列中设计排序,需要先遍历时长小的,如下图所示
如果先遍历了上方的位置,则输出的时长,将不是最少的
所以这里需要使用优先队列

在这里插入图片描述
注释:
1)标记的理由
如果之前访问过某个状态(比如到达过某个点(x, y)), 那么之后若再次访问到了这个点,他的step(操作次数/ 时长等)一定没有之前的小
2)这里虽然有多个朋友但是不需要存下到每一个朋友的时长然后输出最小的。运用了优先队列以后,第一个输出的就是最小的时长

#include<bits/stdc++.h>
using namespace std;

int n, m, st_x, st_y;
// mp用来存放地图,vis标记是否走过某个位置
char mp[205][205], vis[205][205], r[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

struct node{
	int x, y, step;
};
// 队列中数据类型为结构体的优先队列排序写法:
struct cmp{
	bool operator() (node a, node b) {
		return a.step > b.step;  // 优先队列中的排序是反过来了,这里是升序排列
	}
};

bool check(int x, int y) {  // 是否合法
	if(x < 0 || x >= n)	return false;
	if(y < 0 || y >= m)	return false;
	if(mp[x][y] == '#')	return false;
	if(vis[x][y])	return false;
	return true;
}

void bfs() {
	node cur, next;
	priority_queue<node, vector<node>, cmp> q;
	cur.x = st_x, cur.y = st_y, cur.step = 0;  // 初始化为天使位置
	vis[cur.x][cur.y] = 1;  // 标记
	q.push(cur);
	while(!q.empty()) {
		cur = q.top();
		q.pop();
		if(mp[cur.x][cur.y] == 'r') {  // 到达朋友的位置
			printf("%d\n", cur.step);
			return ;
		}
		for(int i = 0; i < 4; i++) {
			// 得到下一个点的坐标
			next.x = cur.x + r[i][0];
			next.y = cur.y + r[i][1];
			if(!check(next.x, next.y))	continue;
			next.step = cur.step + 1;
			// 碰到了守卫, 时长++
			if(mp[next.x][next.y] == 'x')	next.step++; 
			vis[next.x][next.y] = 1;  // 标记
			q.push(next);
		}
	}
	// 遍历所有可能状态后, 若没有在while循环中退出,说明无法救出天使
	printf("Poor ANGEL has to stay in the prison all his life.\n");
	return ;
}

int main() {
	while(~scanf("%d %d", &n, &m)) {
		getchar();
		memset(vis, 0, sizeof(vis));
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				scanf("%c", &mp[i][j]);
				if(mp[i][j] == 'a') {
					st_x = i;
					st_y = j;
				}
			}
			getchar();
		}
		bfs();
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值