ZZULIOJ 1726: 迷宫 (bfs)

时间限制: 1 Sec  内存限制: 128 MB
提交: 1067  解决: 164
[提交] [状态] [讨论版] [命题人:admin]

题目描述

在很多 RPG (Role-playing Games) 游戏中,迷宫往往是非常复杂的游戏环节。通常来说,我们在走迷宫的时候都需要花非常多的时间来尝试不同的路径。但如果有了算法和计算机的帮助,我们能不能有更快的方式来解决这个问题?我们可以进行一些尝试。

现在我们有一个 N 行 M 列的迷宫。迷宫的每个格子如果是空地则可以站人,如果是障碍则不行。在一个格子上,我们可以一步移动到它相邻的 8 个空地上,但不能离开地图的边界或者跨过两个障碍的夹缝。下图是一个移动规则的示例。

为了离开迷宫,我们还需要触发迷宫中所有的机关。迷宫里总共有 K 个机关,每个机关都落在一个不同的空地上。如果我们到达了某个机关所在的格子时,这个机关就会被自动触发,并在触发之后立即消失。我们的目标是按顺序触发所有的 K             个机关,而当最后一个机关被触发时,我们就可以离开迷宫了。

现在我们已经拿到了迷宫地图,并且知道所有障碍、机关的位置。初始时我们位于迷宫的某个非障碍格子上,请你计算我们最少需要移动多少步才能离开迷宫?

输入

输入的第一行是测试数据的组数 T (T ≤ 20)。

扫描二维码关注公众号,回复: 6098234 查看本文章

对于每组测试数据:第一行包含地图的行数 N (2 ≤ N  ≤ 100),列数 M(2 ≤ M  ≤ 100) 和机关的数量 K(1 ≤ K ≤10)。接下来 N 行,每行包含 M 个字符,其中字符 ‘#’ 表示障碍,而 ‘.’ 表示空地。接下来一行描述了我们的初始位置 (x, y),表示我们一开始在第 x 行第 y 列的格子上。这个格子保证是个空地。接下来 K 行,每行给出了一个机关的位置。所有的机关都不会出现在障碍上,并且任意两个机关不会出现在同一个空地上。我们需要按输入给定的顺序触发所有的 K 个机关。

输出

对于每组测试数据,输出离开迷宫所需要的最少步数。如果无论如何都不能离开迷宫,输出 -1。

样例输入 Copy

3
3 3 2
...
...
...
1 1
1 3
2 2
3 3 1
...
.#.
...
1 1
3 3
2 3 1
..#
.#.
1 1
2 3

样例输出 Copy

3
3
-1

来源/分类

[提交] [状态]

思路很简单,就是搜索每两个点间的最短距离,然后加起来,要注意几点。

一个是可能起点就是过程中的点,这个时候就无法完成任务了。

二是搜索的过程中,如果从起点到终点的过程中,路过还未搜索的任务点时,则要跳过;

#include<iostream>
#include<queue>
#include<string.h>
#include<stdio.h>
using namespace std;
int dir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0, 1, 1, -1, -1, 1, -1, -1, 1};
char map[110][110];
bool vis[110][110];
int n, m, k;
int bx, by, ex, ey;
int cnt;
struct node{
	int x, y, t;
}a[110];
bool check(int x, int y)   //判断该点是不是未走的任务点
{
	for(int i = cnt + 1; i <= k; i++)
	{
		if(x == a[i].x && y == a[i].y)
			return 0;
	}
	return 1;
} 
int bfs(int x, int y, int t)
{
	queue<node>q;
	q.push({x, y, t});
	while(!q.empty())
	{
		int x = q.front().x, y = q.front().y, t = q.front().t;
		q.pop();
		if(vis[x][y] || !check(x, y))
			continue;
		vis[x][y] = 1;
		if(x == ex && y == ey)
			return t;
		for(int i = 0; i < 4; i++) //正常上下左右走
		{
			int xx = x + dir[i][0];
			int yy = y + dir[i][1];
			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && map[xx][yy] != '#')
				q.push({xx, yy, t + 1});
		}
		for(int i = 4; i < 8; i++) //走对角线时,要注意被两个#所隔,不能搜索,单独判断
		{
			int xx = x + dir[i][0];
			int yy = y + dir[i][1];
			if(i == 7)
			{
				if((map[x - 1][y] != '#' || map[x][y + 1] != '#') &&xx >= 1 && xx <= n && yy >= 1 && yy <= m && map[xx][yy] != '#')
				q.push({xx, yy, t + 1});
			}
			if(i == 6)
			{
				if((map[x + 1][y] != '#' || map[x][y - 1] != '#') &&xx >= 1 && xx <= n && yy >= 1 && yy <= m && map[xx][yy] != '#')
				q.push({xx, yy, t + 1});
			}
			if(i == 5)
			{
				if((map[x - 1][y] != '#' || map[x][y - 1] != '#') &&xx >= 1 && xx <= n && yy >= 1 && yy <= m && map[xx][yy] != '#')
				q.push({xx, yy, t + 1});
			}
			if(i == 4)
			{
				if((map[x][y + 1] != '#' || map[x + 1][y] != '#') &&xx >= 1 && xx <= n && yy >= 1 && yy <= m && map[xx][yy] != '#')
				q.push({xx, yy, t + 1});
			}
		}
	}
	return -1;
}
int main(){
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int ans = 0;
	//	int flag = 1;
		scanf("%d%d%d", &n, &m, &k);
		for(int i = 1; i <= n; i++)
			scanf("%s", map[i] + 1);
		scanf("%d%d", &a[0].x, &a[0].y);
		for(int i = 1; i <= k; i++)
		{
			scanf("%d%d", &a[i].x, &a[i].y);
		}
		for(int i = 2; i <= k; i++)   // 判断 除第一个点外,其他任务点有没有跟起点撞的
		{
			if(a[i].x == a[0].x && a[i].y == a[0].y)
			{
				ans = -1;
				break;
			}
			
		}
		cnt = 1;
		if(ans != -1)
		    for(int i = 1; i <= k; i++) 
		    {
		        memset(vis, 0, sizeof vis);
		        bx = a[i - 1].x, by = a[i - 1].y;//上一个任务点为起点
			ex = a[i].x, ey = a[i].y; //当前任务点为终点
			int v = bfs(bx, by, 0);
			if(v != -1)
				ans += v;
			else
			{
				ans = -1;
				break;
			}
			cnt++;
		    }
		cout << ans << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43731933/article/details/89669289