卡片换位
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
输入格式:
输入两行6个字符表示当前的局面
输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
例如,输入:
* A
**B
程序应该输出:
17
再例如,输入:
A B
***
程序应该输出:
12
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
思路:用pair<int, int> 来描述一个坐标,对于每个局面都只记录A,B,空格的坐标,剩下三个*不关注他们在哪,不用记录。对于每个状态转移,视为空格在移动。然后BFS。用set记录已出现过的局面;
- 广度优先搜索
#include "bits/stdc++.h" using namespace std; typedef long long LL; typedef pair<int, int> PII; struct node { // a表示A, b表示B, c表示空格 PII a, b, c; // 因为set要实现小于号所以这里随便敲个小于号。只要能实现排序就行 friend bool operator < (node n, node m) { if (n.a != m.a) { return n.a < m.a; } else if (n.b != m.b) { return n.b < m. b; } else { return n.c < m.c; } } } n; PII A, B; char mp[2][4]; // 这里的pair表示当前局面和步数 queue<pair<node, int> > q; // 记录出现过的局面 set<node> st; void check(PII c, int step) { // 越界情况 if (c.first < 0 || c.first > 1 || c.second < 0 || c.second > 2) { return; } node m; m.c = c; m.a = (n.a == c) ? n.c : n.a; m.b = (n.b == c) ? n.c : n.b; // 新局面之前出现过 if (st.count(m)) { return; } st.insert(m); q.push({m, step + 1}); } void BFS() { while (!q.empty()) { n = q.front().first; int step = q.front().second; q.pop(); // 已到达目标状态 if (n.a == B && n.b == A) { printf("%d ", step); return; } check({n.c.first - 1, n.c.second}, step); check({n.c.first, n.c.second - 1}, step); check({n.c.first + 1, n.c.second}, step); check({n.c.first, n.c.second + 1}, step); } } int main() { gets(mp[0]); gets(mp[1]); // 找到原图里A, B, 空格的位置 for (int i = 0; i < 2; i++) { for (int j = 0; j < 4; j ++) { if (mp[i][j] == ' ') { n.c = {i, j}; } if (mp[i][j] == 'A') { n.a = A = {i, j}; } if (mp[i][j] == 'B') { n.b = B = {i, j}; } } } q.push({n, 0}); st.insert(n); BFS(); return 0; }
这题如果会BFS还是很好想的,但是check那里想了好久。check写的好会使代码比较整洁不易错。但是没有OJ可以提交这题,所以如果代码有问题请指出。