YTU Saving Tang Monk

文章描述了一个关于迷宫的问题,迷宫中包含起点、终点、空地、墙、蛇和钥匙,要求孙悟空在救唐僧的同时收集所有必要的钥匙。使用优先队列和广度优先搜索算法寻找从起点到终点的最短路径和时间。如果无法完成任务,则输出“impossible”。
摘要由CSDN通过智能技术生成

题目描述

有宽度不超过 100 的正方形迷宫如下所示:
K . S # # 1 1 # T “K”代表开始孙悟空所处的位置,“T”代表唐僧所处的位置,“.”代表空地,“#”代表墙,“S”代表此处有一条蛇,数字 nnn 代表此处有钥匙且要是的种类编号是 nnn(0<n≤90 \lt n \le 90<n≤9)。孙悟空要去救唐僧,他只能朝上、下、左、由四个方向走,走到相邻的格子需要花 1min1 min1min。“#”处不能走。走到“S”处则需要停留 1min1 min1min。走到放钥匙处,如果钥匙的种类编号为 nnn,且孙悟空已经得到了编号为 1,2........n−1 的钥匙,则它可以取走该钥匙,否则就只能过而不取。一共有 m 种钥匙(0<m≤90 \lt m \le 90<m≤9),孙悟空走到唐僧处时,必须集齐 mmm 种钥匙才能救唐僧,否则只能过而不救。问孙悟空要救唐僧,最少要花多长时间。
 

输入

输入包含多个测试样例。对于每个测试样例,第一行包含两个整数 n和 m(0<n≤1000 ,0<m≤90 ),随后输入一个 n*n 的矩阵。当输入的样例为 n=0 和 m=0 时,输入终止。

输出

对于每行测试样例,输出孙悟空救唐僧所需要的最短时间(以分钟为单位)。如果孙悟空无法完成该任务,则输出“impossible”。

输入输出样例

样例输入 #1

这个需要分层次来写每一个不同的钥匙为一层,同时最短路径广搜,然后你需要判断一下步数和钥匙的数量当步数不同的时候肯定小的优先,相同时看钥匙大的优先你需要用到优先队列

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
char a[105][105];
int vis[105][105][105];
int n,m;
int row1, line1;
int b[4] = { 0,0,1,-1 };
int c[4] = { 1,-1,0,0 };
bool flag;
struct node
{
	int row;
	int line;
	int step;
	int k;
	friend bool operator < (node a, node b)
	{
		if (a.step != b.step)
			return a.step > b.step;
		return a.k < b.k;
	}
};
priority_queue<node>r;
int main()
{
	while (cin >> n >> m)
	{
		if (n == 0 && m == 0)
			break;
		flag = false;
		memset(vis,0, sizeof(vis));
		memset(a, '.', sizeof(a));
		while (!r.empty())
		{
			r.pop();
		}
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				cin >> a[i][j];
				if (a[i][j] == 'T')
				{
					row1 = i;
					line1 = j;
				}
				if (a[i][j] == 'K')
				{
					node start;
					start.row = i;
					start.line = j;
					start.step = 0;
					start.k = 0;
					vis[i][j][start.k] = 1;
					r.push(start);
				}
			}
		}
		while (!r.empty())
		{
			if (r.top().row == row1 && r.top().line == line1&&r.top().k==m)
			{
				flag = true;
				cout << r.top().step << endl;
				break;
			}
			for (int i = 0; i < 4; i++)
			{
				int xx = r.top().row + b[i];
				int yy = r.top().line + c[i];
				if (vis[xx][yy][r.top().k] == 0 && a[xx][yy] != '#' && xx >= 0 && xx < n && yy>=0 && yy < n)
				{
					node temp;
					if (a[xx][yy] == '.')
					{
						vis[xx][yy][r.top().k] = 1;
						temp.row = xx;
						temp.line = yy;
						temp.k = r.top().k;
						temp.step = r.top().step + 1;
						r.push(temp);
					}
					else if (a[xx][yy] == 'S')
					{
						vis[xx][yy][r.top().k] = 1;
						temp.row = xx;
						temp.line = yy;
						temp.k = r.top().k;
						temp.step = r.top().step + 2;
						r.push(temp);
					}
					else if (a[xx][yy] == 'T')
					{
						vis[xx][yy][r.top().k] = 1;
						temp.row = xx;
						temp.line = yy;
						temp.k = r.top().k;
						temp.step = r.top().step + 1;
						r.push(temp);
					}
					else
					{
						vis[xx][yy][r.top().k] = 1;
						int b = a[xx][yy] - '0';
						temp.row = xx;
						temp.line = yy;
						temp.step = r.top().step + 1;
						if (b == r.top().k + 1)
						{
							temp.k = b;
						}
						else
						{
							temp.k = r.top().k;
						}
						r.push(temp);
					}
				}
			}
			r.pop();
		}
		if (!flag)
			cout << "impossible" << endl;
	}
}
3 1
K . S
# # 1
1 # T
3 1
K # T
. S #
1 # .
3 2
K # T
. S .
2 1 .
0 0

样例输出 #1

复制

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值