ICPC Asia Taipei-Hsinchu Regional 2019 Rush Hour Puzzle (矩阵哈希 + BFS)

Problem Description

Rush Hour is a puzzle game invented by Nob Yoshigahara in the 19701970s. It is now being manufactured by ThinkFun. The board is a 6 \times 66×6 grid with grooves in the tiles to allow vehicles to slide. Cars and trucks are both one square wide, but cars are two squares long and trucks are three squares long. Vehicles can only be moved forward or backward along a straight line on the grid. The goal of the game is to get the only red car totally out through the exit of the board by moving the other vehicles out of its way. Figure 1 gives an example of Rush Hour puzzle.

A-1.png

Figure 1: An example of Rush Hour puzzle.

We give each vehicle of a puzzle a unique id, numbered from 11 to the number of vehicles, in which the red car's id is 11. The board information of a puzzle is represented by a 6 \times 66×6 matrix, named board matrix. Each entry of a board matrix is the id of the vehicle placed on that groove, and the entries are filled with 00 if there exists no vehicle on those grooves. The exit of the board is located at the right end side of the 33rd row. Figure 2 shows the board matrix corresponding to the puzzle in Figure 1.

Moving a piece (car or truck) by one unit (a groove) is called a step. A puzzle is easy if it can be solved (the red car totally out through the exit of the board) in no more than 10 steps. Please write a program to judge whether a puzzle is easy or not.

A-2.png

Figure 2: The board matrix corresponding to the puzzle in Figure 1.

Input Format

The input contains 6 lines, each line indicates the content (6 integers separated by a blank) of each row of a board matrix.

Output Format

Output the minimum number of steps for solving the input puzzle if the puzzle is easy, otherwise output -1.

Technical Specification

  • There are at most 1010 vehicles on the board for each puzzle.
  • Only the red car can be moved out of the board for each puzzle.

输出时每行末尾的多余空格,不影响答案正确性

样例输入

2 2 0 0 0 7
3 0 0 5 0 7
3 1 1 5 0 7
3 0 0 5 0 0
4 0 0 0 8 8
4 0 6 6 6 0

样例输出

-1

样例输入

0 2 0 6 6 0
0 2 0 0 7 0
0 3 1 1 7 0
0 3 4 4 8 0
0 5 5 5 8 0
0 0 0 0 0 0

样例输出

6

题目大意 :

       有一个6 * 6的方格,其中包含了1 * 2的汽车, 1 * 3的卡车,汽车和卡车均只能沿着车头或者车尾移动且总数不超过10,现在要让编号为1的车移动到出口位置,最少需要多少时间,如果时间超过10或无法走到出口,输出-1

思路 :

       这道题特别之处就在于非常麻烦,不过本质上还是BFS,每次保存一个状态,当状态满足时即为最短,所以可以将地图存到结构体当中,并且用map + 矩阵哈希来标记是否访问过,这样问题就简化成了最基础的BFS迷宫,剩下就是判断这张图中哪些方块可以移动就好。

Accepted code

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

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x));
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct Mp
{
	int step;
	int mp[8][8];
}now, nxt;
const int n = 6;
const int B = 233;
int a[8][8];     // 矩阵的初值
int dir[8][8];   // 每个值的方向1左右2上下
unordered_map <ll, bool> vis; // 哈希矩阵标记访问

ll has(int s[][8]) {            // 矩阵的哈希值
	ll tot = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			tot = (tot * B + s[i][j]) % MOD;
		}
	}
	return tot;
}
void Direct(int p[][8]) {            // 生成方向数组
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (!p[i][j])
				continue;
			if (p[i][j] == p[i][j - 1] || p[i][j] == p[i][j + 1])
				dir[i][j] = 1;
			else if (p[i][j] == p[i - 1][j] || p[i][j] == p[i + 1][j])
				dir[i][j] = 2;
		}
	}
}

int bfs() {
	queue <Mp> q;
	now.step = 0;
	MEM(now.mp, 0); MPY(now.mp, a);
	q.push(now);
	ll res = has(now.mp);
	vis[res] = true;       // 标记初始矩阵
	while (!q.empty()) {
		now = q.front();
		q.pop();
		if (now.step > 8)                // 超过步数
			continue;  
		if (now.mp[3][5] == 1 && now.mp[3][6] == 1)  // 走到出口
			return now.step;
		Direct(now.mp);                              // 生成方向矩阵
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (!now.mp[i][j])
					continue;
				if (dir[i][j] == 1) {   //左右
					int L = j, R = j;
					while (now.mp[i][L] == now.mp[i][j])
						L--;
					L++;                        // 最左
					while (now.mp[i][R] == now.mp[i][j])
						R++;
					R--;                        // 最右
					if (L >= 2 && !now.mp[i][L - 1]) { // 左可以走
						MEM(nxt.mp, 0);
						MPY(nxt.mp, now.mp);
						nxt.mp[i][L - 1] = now.mp[i][j];
						nxt.mp[i][R] = 0;
						nxt.step = now.step + 1;
						ll res = has(nxt.mp);
						if (vis.count(res) == NULL)
							vis[res] = true, q.push(nxt);
					}
					if (R <= 5 && !now.mp[i][R + 1]) { // 右可以走
						MEM(nxt.mp, 0);
						MPY(nxt.mp, now.mp);
						nxt.mp[i][R + 1] = now.mp[i][j];
						nxt.mp[i][L] = 0;
						nxt.step = now.step + 1;
						ll res = has(nxt.mp);
						if (vis.count(res) == NULL)
							vis[res] = true, q.push(nxt);
					}
				}
				else {  // 上下
					int D = i, U = i;
					while (now.mp[D][j] == now.mp[i][j])
						D++;
					D--;                         // 最下
					while (now.mp[U][j] == now.mp[i][j])
						U--;
					U++;                         // 最上
					if (D <= 5 && !now.mp[D + 1][j]) { // 下可以走
						MEM(nxt.mp, 0);
						MPY(nxt.mp, now.mp);
						nxt.mp[D + 1][j] = now.mp[i][j];
						nxt.mp[U][j] = 0;
						nxt.step = now.step + 1;
						ll res = has(nxt.mp);
						if (vis.count(res) == NULL)
							vis[res] = true, q.push(nxt);
					}
					if (U >= 2 && !now.mp[U - 1][j]) { // 上可以走
						MEM(nxt.mp, 0);
						MPY(nxt.mp, now.mp);
						nxt.mp[U - 1][j] = now.mp[i][j];
						nxt.mp[D][j] = 0;
						nxt.step = now.step + 1;
						ll res = has(nxt.mp);
						if (vis.count(res) == NULL)
							vis[res] = true, q.push(nxt);
					}
				}
			}
		}
	}
	return -1;
}

int main()
{
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			sc("%d", &a[i][j]);
		}
	}
	int ans = bfs();
	if (ans == -1)
		printf("-1\n");
	else
		printf("%d\n", ans + 2);
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/105468944