#93-[bfs啊bfs]孤岛营救

Description

1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 n 行,东西方向被划分为 m 列, 于是整个迷宫被划分为 n×m  个单元。每一个单元的位置可用一个有序数对 (单元的行号, 单元的列号) 来表示。南北或东西方向相邻的 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成 p 类, 打开同一类的门的钥匙相同,不同类门的钥匙不同。

大兵瑞恩被关押在迷宫的东南角,即 (n,m) 单元里,并已经昏迷。迷宫只有一个入口, 在西北角。也就是说,麦克可以直接进入 (1,1) 单元。另外,麦克从一个单元移动到另一个 相邻单元的时间为 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。

Input

第一行有三个整数,分别表示 n,m,p 的值。
第二行是一个整数k,表示迷宫中门和墙的总数。
第 i+2行 (1≤i≤k),有 5 个整数,依次为 xi1,yi1,xi2,gi:当 gi≥1时,表示 (xi1,yi1) 单元与 (xi2,yi2) 单元之间有一扇第 gi 类的门,当 gi=0时, 表示 (xi1,yi1) 单元与 (xi2,yi2) 单元之间有一堵不可逾越的墙。
第 k+3 行是一个整数 s,表示迷宫中存放的钥匙总数。
第 k+3+j行 (1≤j≤s),有 3 个整数,依次为 xi1,yi1,qi​​,表示第 j 把钥匙存放在 (xi1,yi1) 单元里,并且第 j 把钥匙是用来开启第 qi 类门。
输入数据中同一行各相邻整数之间用一个空格分隔。

Output

输出麦克营救到大兵瑞恩的最短时间。如果问题无解,则输出 −1。

Sample Input

4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0 
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2 
4 2 1

Sample Output

14

HINT

 

【数据范围与提示】

  • ∣xi1−xi2∣+∣yi1−yi2∣=1,  0≤gi≤p
  • 1≤qi≤p
  • n,m,p≤10,  k<150

基本广搜

#include 
#include 
#include 

#define SIZE 20

using namespace std;

struct node
{
	int x, y, step;
	bool key[SIZE];
};

// 12维数组
queue q;
int way[SIZE][SIZE][SIZE][SIZE], n, m, p;
bool key[SIZE][SIZE][2][2][2][2][2][2][2][2][2][2], visited[SIZE][SIZE], havekey[SIZE][SIZE][SIZE];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

bool check(int x, int y, int r, int c, bool havekey[]) // 判断能不能走
{
	int temp = way[x][y][r][c], i;
	
	if (((!r) || (r > n)) || ((!c) || (c > m)))
	{
		return false;
	}
	if (!temp)
	{
		return false;
	}
	if (~temp)
	{
		if (!havekey[temp])
		{
			return false;
		}
	}
	bool &f = key[r][c][havekey[1]][havekey[2]][havekey[3]][havekey[4]][havekey[5]][havekey[6]][havekey[7]][havekey[8]][havekey[9]][havekey[10]]; // 很暴力
	if (f)
	{
		return false;
	}
	visited[r][c] = true;
	f = true;
	
	return true;
}

int main(void)
{
	int k, i, j, x, y, r, c;
	bool a[11] = {};
	
	memset(way, -1, sizeof (way));
	
	scanf("%d%d%d%d", &n, &m, &p, &k);
	while (k--)
	{
		scanf("%d%d%d%d%d", &x, &y, &r, &c, &i);
		way[r][c][x][y] = way[x][y][r][c] = i;
	}
	scanf("%d", &k);
	while (k--)
	{
		scanf("%d%d%d", &x, &y, &i);
		havekey[x][y][i] = true; // 一个格子可能有多个钥匙
	}
	
	visited[1][1] = key[1][1][a[1]][a[2]][a[3]][a[4]][a[5]][a[6]][a[7]][a[8]][a[9]][a[10]] = true; // 很暴力
	q.push({1, 1, 0, {}});
	for (i = 1; i <= p; ++i)
	{
		if (havekey[1][1][i])
		{
			q.front().key[i] = true;
		}
	}
	while (!q.empty()) // 基本广搜
	{
		x = q.front().x;
		y = q.front().y;
		for (i = 0; i < 4; ++i)
		{
			r = x + dx[i];
			c = y + dy[i];
			if (check(x, y, r, c, q.front().key))
			{
				if ((r == n) && (c == m)) // 到达终点,输出最短路径
				{
					printf("%d", q.front().step + 1);
					return 0;
				}
				q.push({r, c, q.front().step + 1, {}});
				for (j = 1; j <= p; ++j)
				{
					if ((q.front().key[j]) || (havekey[r][c][j]))
					{
						q.back().key[j] = true;
					}
				}
			}
		}
		q.pop();
	}
	
	printf("-1"); // 到不了,输出-1
	
	return 0;
}

 

你可能感兴趣的:(刷题,gdgzoi刷题)