UVa1063/LA3807 Marble Game
UVa1063/LA3807 Marble Game
- 题目链接
- 题意
- 输入格式
- 输出格式
- 分析
- AC 代码
题目链接
本题是2007年icpc世界总决赛的F题
题意
滚球游戏由一个 n×n(2≤n≤4)网格棋盘和 m 个小球组成。棋盘上恰好有 m 个单元格里有洞。球和洞均编号为 1~m。滚球游戏的目标为把每个球滚到编号相同的洞中。单元格的 4 条边上可能会有墙,可以阻挡球的滚动(见后)。
每次可以把棋盘朝着上下左右 4 个方向之一微微抬起,然后所有球同时朝另一个方向滚动,直到碰到墙、洞或者另一个球。球在滚动的过程不能跳起(因而无法越过墙、其他球或者洞),也不能离开棋盘(整个棋盘的四周都有墙)。每个单元格恰好能容纳一个球。当球落入洞之后,洞将被填平,使得今后可以有其他球经过。入洞的球将无法出洞。
下图所示是一个滚球游戏及其解法。你的任务是解决任意一个 n×n 棋盘上的滚球游戏,找出移动次数最小的解,输出其长度。
输入格式
输入包含多组数据。每组数据第一行为 3 个整数 N、M、W(2≤N≤4,M>0)N、M、W\;(2 \le N \le 4,M>0)N、M、W(2≤N≤4,M>0),分别表示网格尺寸、球的数量(也是洞的数量)和墙的数量。接下来 MMM 行每行 2 个数字,依次代表每个球的行列编号。接下来 MMM 行每行 2 个数字,依次代表每个洞的行列编号。最后 WWW 行每行 4 个整数,分别表示墙两边格子的行列编号。输入结束标志为三个 0。
输出格式
对于每组数据,如果有解则输出一行 Case k: ans moves,无解则输出一行 Case k: impossible,其中 k 为测试数据的编号(编号从 1 开始),ans 为最小移动次数。每组数据输出一行后还需要再输出一个空行。
分析
本题直接广度优先搜索,模拟游戏过程直到找到解或者判定出无解即可。
AC 代码
#include <iostream>
#include <cstring>
using namespace std;#define M 50001
#define N 4
int a[N][N], e[N][N], f[N][N], h[N][N], q[M], m, n, w, c, kase = 0;
long long s[M], g[M]; bool l[N][N], r[N][N], t[N][N], b[N][N];bool term() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) if (f[i][j]) return false;return true;
}void decode(long long x, long long y) {for (int i=n-1; i>=0; --i) for (int j=n-1; j>=0; --j) a[i][j] = x & 15, h[i][j] = y & 15, x >>= 4, y >>= 4;
}void insert() {long long x = 0, y = 0;for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) x = x<<4 | e[i][j], y = y<<4 | f[i][j];int k = x % M;while (s[k]) {if (s[k] == x) return;++ k;}s[k] = x; g[k] = y; q[c++] = k;
}bool move_l() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) e[i][j] = a[i][j], f[i][j] = h[i][j];for (int i=0; i<n; ++i) for (int j=n-2, k; j>=0; --j) if (f[i][j]) {for (k=j+1; !l[i][k] && !f[i][k]; ++k) if (e[i][k]) {if (e[i][k] != f[i][j]) return false;e[i][k] = f[i][j] = 0; break;}}for (int i=0; i<n; ++i) for (int j=0, k; j<n; ++j) if (!e[i][j]) {for (k=j; !r[i][k]; ++k) if (e[i][k]) break;if (k > j) e[i][j] = e[i][k], e[i][k] = 0;}return true;
}bool move_r() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) e[i][j] = a[i][j], f[i][j] = h[i][j];for (int i=0; i<n; ++i) for (int j=1, k; j<n; ++j) if (f[i][j]) {for (k=j-1; !r[i][k] && !f[i][k]; --k) if (e[i][k]) {if (e[i][k] != f[i][j]) return false;e[i][k] = f[i][j] = 0; break;}}for (int i=0; i<n; ++i) for (int j=n-1, k; j>0; --j) if (!e[i][j]) {for (k=j; !l[i][k]; --k) if (e[i][k]) break;if (k < j) e[i][j] = e[i][k], e[i][k] = 0;}return true;
}bool move_t() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) e[i][j] = a[i][j], f[i][j] = h[i][j];for (int j=0; j<n; ++j) for (int i=n-2, k; i>=0; --i) if (f[i][j]) {for (k=i+1; !t[k][j] && !f[k][j]; ++k) if (e[k][j]) {if (e[k][j] != f[i][j]) return false;e[k][j] = f[i][j] = 0; break;}}for (int j=0; j<n; ++j) for (int i=0, k; i<n; ++i) if (!e[i][j]) {for (k=i; !b[k][j]; ++k) if (e[k][j]) break;if (k > i) e[i][j] = e[k][j], e[k][j] = 0;}return true;
}bool move_b() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) e[i][j] = a[i][j], f[i][j] = h[i][j];for (int j=0; j<n; ++j) for (int i=1, k; i<n; ++i) if (f[i][j]) {for (k=i-1; !b[k][j] && !f[k][j]; --k) if (e[k][j]) {if (e[k][j] != f[i][j]) return false;e[k][j] = f[i][j] = 0; break;}}for (int j=0; j<n; ++j) for (int i=n-1, k; i>=0; --i) if (!e[i][j]) {for (k=i; !t[k][j]; --k) if (e[k][j]) break;if (k < i) e[i][j] = e[k][j], e[k][j] = 0;}return true;
}int solve() {for (int i=0; i<n; ++i) for (int j=0; j<n; ++j)e[i][j] = f[i][j] = 0, l[i][j] = j==0, r[i][j] = j==n-1, t[i][j] = i==0, b[i][j] = i==n-1;for (int i=1, j, k; i<=m; ++i) cin >> j >> k, e[j][k] = i;for (int i=1, j, k; i<=m; ++i) cin >> j >> k, e[j][k] == i ? e[j][k] = 0 : f[j][k] = i;for (int i=0; i<w; ++i) {int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2;if (r1 == r2) r[r1][min(c1, c2)] = l[r1][max(c1, c2)] = true;else t[max(r1, r2)][c1] = b[min(r1, r2)][c1] = true;}for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) if (e[i][j] && f[i][j] && e[i][j] != f[i][j]) return -1;if (term()) return 0;memset(s, c = 0, sizeof(s)); insert();int h = 0, t = c, d = 1;while (h < t) {long long x = s[q[h]], y = g[q[h++]]; decode(x, y);if (move_l()) {if (term()) return d;insert();}if (move_r()) {if (term()) return d;insert();}if (move_t()) {if (term()) return d;insert();}if (move_b()) {if (term()) return d;insert();}if (h == t) t = c, ++d;}return -1;
}int main() {while (cin >> n >> m >> w && n) {int k = solve();cout << "Case " << ++kase << ": ";k < 0 ? cout << "impossible" << endl << endl : cout << k << " moves" << endl << endl;}return 0;
}