卡片换位
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
输入格式:
输入两行6个字符表示当前的局面
输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
例如,输入:
程序应该输出:
17
再例如,输入:
程序应该输出:
12
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
解题过程:
这道题一开始用bfs的时候发现结果怎么也不对,找了很久发现自己写的是其他字符位置不变,只是A和B互换位置为bfs的返回条件。
之后看了一下题,发现A和B互换位置即可,其他字符的位置随便怎么样都行。。 所以以后做题的时候一定要认真审题,不要急躁。
思路:用一个string保存每一个局面的状态,图中的数字表示string的下标i,当i-1,i+1,i-3,i+3分别表示向左,向右,向上,向下走。使用set对该局面(string)进行判重。
但是注意到用如下的图有限制,比如3-1 = 2,但是3和2并不相邻。
所以将每一个局面的状态的保存修改为如下string,string的下标3不使用(代码中将其赋予了#),此时i-1,i+1,i-4,i+4分别表示向左,向右,向上,向下走,这样就消除了边界的影响。
#include<iostream>
#include<string>
#include<queue>
#include<set>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stdio.h> using namespace std; int dx[] = {,-,,-}; string start_str;
int orig_posA;
int orig_posB; struct node
{
int x; // 空格字符所在的下标
string str;
int step;
}; void bfs(node nod)
{
queue<node> Q;
Q.push(nod);
set<string> sset;
sset.insert(nod.str); node t, p;
while(!Q.empty())
{
t = Q.front();
Q.pop(); /* 一开始把判断条件错误地写成了 if(t.str == end_str), end_str表示把
初始字符串中A,B位置互换后的字符串, 但是这样也把其他字符的位置固定死了 */
// 正解:A和B的位置与一开始的位置互换即可,其他字符的位置随意
if(t.str.find('B') == orig_posA && t.str.find('A') == orig_posB)
{
cout << t.step << endl;
return;
} for(int i = ; i < ; ++i)
{
int xx = t.x + dx[i];
if((xx >= && xx <= ) || (xx >= && xx <= ))
{
string ss = t.str;
swap(ss[t.x], ss[xx]);
p.x = xx;
p.str = ss;
p.step = t.step + ;
if(sset.count(p.str) == )
{
sset.insert(p.str);
Q.push(p);
} }
}
} } int main()
{
string s1;
string s2;
getline(cin, s1);
getline(cin, s2); // 下标3不使用,此处将其赋值为了#
start_str = s1 + '#' + s2; int start_x = start_str.find(' ');
orig_posA = start_str.find('A');
orig_posB = start_str.find('B'); node nod;
nod.x = start_x;
nod.str = start_str;
nod.step = ;
bfs(nod); return ;
}