UVa1008/LA2240 A Vexing Problem
UVa1008/LA2240 A Vexing Problem
- 题目链接
- 题意
- 输入格式
- 输出格式
- 分析
- AC 代码
题目链接
本题是2001年icpc世界总决赛的I题
题意
Vexed 游戏是James McCombe 发明的一种类似俄罗斯方块的游戏。在游戏中,一面木头墙上放置了一些标有字母的白色石块。
如果某个石块的左边(或者右边)是空的,那么该石块可以向左(或者向右)移动一步,木头墙永远不能移动,悬空的石块会自动下掉。每个石块都有一个标记,两个或更多具有相同标记的石块相碰时会形成石块群,石块群会自动消失。如果同时形成了多个石块群,那么它们会一起同时消失。石块群消失后,悬空的石块同样会自动下掉,下掉后石块群同样会消失……如此循环,直到石块不再变化为止。游戏的目标就是让所有的石块消失。
如下图(a)到(h)所示就是一个从初始状态到石块全部消失的游戏过程:首先上面的“Y”石块左移,这样两个“Y”石块形成石块群自动消失;然后上面的“X”石块右移,右移后下掉,这样两个“X”石块也形成石块群自动消失。
下图所示是另一个游戏过程:首先最左边的“Z”右移(图a),形成“X”、“Z”石块群(图b);石块群消失后,又形成“Y”、“Z”、“X”石块群;石块群消失后,最后形成“X”石块群,“X”石块群消失后游戏结束。
写一个程序,任意给出一个游戏,给出步数最少的解。行数 R 和列数 C 满足 4≤R,C≤9,第一列、最后一列和最后一行保证为墙(#)输入保证存在一个不超过11 步的解。
输入格式
输入包含多组组测试数据。每组测试数据第一行包含整数 R,C 和一个字符串,分别代表行数、列数、测试数据的名称。接下来 R 行每行 C 个字符(#代表墙,-代表空,A∼ZA\sim ZA∼Z 代表不同类型的石头)。输入以 0 0 END结束。
输出格式
对于每组测试数据,输出最少的操作次数和方案,多解时输出任意一个方案即可,格式参照样例:
样例输入 | 样例输出 |
---|---|
4 5 SAMPLE-01 | SAMPLE-01: Minimum solution length = 2 |
#A–# | (B,1,3,L) (A,0,1,R) |
##-B# | SAMPLE-02: Minimum solution length = 9 |
#AB## | (Y,0,3,R) (Z,4,5,L) (X,1,3,R) (Z,1,2,R) |
##### | (Z,1,3,R) (X,3,4,R) (X,3,2,R) (X,4,5,L) |
(X,1,5,L) | |
#–Y–# | |
#-ZX-X# | |
#-##-## | |
#-XZ–# | |
####YZ# | |
####### | |
0 0 END |
分析
本题限时30s,暴力法能过,直接 BFS 并用集合对状态判重即可。
AC 代码
#include <iostream>
#include <set>
using namespace std;#define block(c) (c != '-' && c != '#')
int f[64], s[11], r, c, t; char name[30];int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);
}struct node {char s[9][9], ch, d; int p, x, y;bool operator< (const node &e) const {for (int i=0; i<r; ++i) for (int j=1; j<c; ++j) if (s[i][j] != e.s[i][j]) return s[i][j] < e.s[i][j];return false;}void rem() {bool g = true;while (g) {for (int i=r-1; i>=0; --i) for (int j=1; j<c; ++j) if (block(s[i][j]))for (int k=i+1; k<r && s[k][j] == '-'; ++k) s[k][j] = s[k-1][j], s[k-1][j] = '-';g = false;for (int i=0, k=0; i<r; ++i) for (int j=1; j<c; ++j, ++k) f[k] = k;for (int i=0, k=0, cc=c-1; i<r; ++i) for (int j=1; j<c; ++j, ++k) if (block(s[i][j])) {if (s[i][j] == s[i-1][j]) f[find(k)] = find(k-cc);if (s[i][j] == s[i][j-1]) f[find(k)] = find(k-1);}for (int i=0, k=0, cc=c-1, x; i<r; ++i) for (int j=1; j<c; ++j, ++k)if ((x = find(k)) != k) g = true, s[i][j] = s[x/cc][x%cc+1] = '-';}}bool empty() const {for (int i=0; i<r; ++i) for (int j=1; j<c; ++j) if (block(s[i][j])) return false;return true;}
} q[1000000];struct cmp {bool operator() (int i, int j) const {return q[i] < q[j];}
};set<int, cmp> vis;bool ext(const int h) {for (int i=0; i<r; ++i) for (int j=1; j<c; ++j) if (block(q[h].s[i][j])) {if (q[h].s[i][j-1] == '-') {q[t] = q[h]; q[t].ch = q[h].s[i][j]; q[t].d = 'L'; q[t].p = h; q[t].x = i; q[t].y = j;q[t].s[i][j-1] = q[h].s[i][j]; q[t].s[i][j] = '-'; q[t].rem();if (q[t].empty()) return true;if (!vis.count(t)) vis.insert(t++);}if (q[h].s[i][j+1] == '-') {q[t] = q[h]; q[t].ch = q[h].s[i][j]; q[t].d = 'R'; q[t].p = h; q[t].x = i; q[t].y = j;q[t].s[i][j+1] = q[h].s[i][j]; q[t].s[i][j] = '-'; q[t].rem();if (q[t].empty()) return true;if (!vis.count(t)) vis.insert(t++);}}return false;
}void find(int x, int &d) {int dd = 0;if (q[x].p) find(q[x].p, dd);s[dd] = x; d = dd+1;
}void output() {int d = 0; find(t, d);cout << name << ": Minimum solution length = " << d;for (int i=0; i<d; ++i) {if ((i&3) == 0) cout << endl;cout << '(' << q[s[i]].ch << ',' << q[s[i]].x << ',' << q[s[i]].y << ',' << q[s[i]].d << ')';if ((i&3) < 3) cout << ' ';}cout << endl;
}void solve() {for (int i=0; i<r; ++i) for (int j=0; j<c; ++j) cin >> q[0].s[i][j];--r; --c; t = 1; vis.clear(); vis.insert(0);for (int h=0; h<t; ++h) if (ext(h)) return output();int cc = 1;
}int main() {while (cin >> r >> c >> name && r) solve();return 0;
}