励志用尽量少的代码做高效表达
问题描述
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
输入格式:
输入两行6个字符表示当前的局面
输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
建议:这是一道BFS或DFS的变形题,对初学者来说还是有一点压力的。如果你对搜索模板题还没有掌握的话,那么请先比较熟练的掌握深搜、广搜模板后再来尝试解决。
思路分析
思路一:DFS
一开始以为需要“数字华容道”游戏的策略,或者需要一些技巧和推动, 也因此迟迟不敢动笔, 网搜后发现,直接用DFS暴力推过去就可以:
以空格为起点, 上下左右探索, 每次回溯交换位置即可。(-_-|| 我还是不够暴力)
有一点需要注意:
一般来讲,我们做DFS的题时,都是习惯先判断该步是否满足条件,如果满足,则对应的标记数组置1, 回溯,回溯结束后标记数组置0.
但对于本题来说,则需要用if循环判断是否满足条件,共有三种回溯的可能,这样如果每种可能都重复以上的三步, 那么代码就会冗余、易错。
解决办法是:对于每种可能的回溯情况, 无论是否符合,都进行回溯,在下一次回溯开始前统一判断是否符合条件, 如果符合,则vis再置1。这样不仅大大精简了代码,也提高了代码的可读性和效率
思路二:BFS
明天更新, 请持续关注~
一些小技巧:
1. 要使用getchar()处理输入的字符,因为存在空格,scanf或cin无法识别,并且这样的数也很难被存进数组里, 本解法没有使用数组, 以几个数的相对位置来模拟出数组, 请读者细心体会。
2、涉及到坐标的运算时,用结构体模拟坐标求解,往往更为简洁。
3、dfs函数中有一行代码为:if(step > Min) return;
在求最短路时加此代码,可以很好的提高代码效率
DFS解法代码展示
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int Min = inf;
struct{
int x, y;
}a, b, k;
int vis[3][3][3][3][3][3]; //标记数组,标记某点是否走过
int Next[4][2] = {
{
1,0}, {
-1, 0}, {
0, 1}, {
0, -1}}; //分别代表向右,向左,向上,向下走
void dfs(int x1, int y1, int x2, int y2, int x, int y, int step) {
if(step > Min) return; //提高效率,步数超过直接return;
if(x1==b.x && y1==b.y && x2==a.x && y2==a.y) {
Min = min(step, Min);
return;
}
//先判断越界
if(x<0 || x>1 || y<0 || y>2) return;
if(vis[x1][y1][x2][y2][x][y] == 1) return;
vis[x1][y1][x2][y2][x][y] = 1;
for(int i = 0; i < 4; i++) {
int tx = x+Next[i][0];
int ty = y+Next[i][1];
if(tx==x1 && ty==y1)
dfs(x, y, x2, y2, x1, y1, step+1);
else if(tx==x2 && ty==y2)
dfs(x1, y1, x, y, x2, y2, step+1);
else
dfs(x1, y1, x2, y2, tx, ty, step+1);
}
vis[x1][y1][x2][y2][x][y] = 0;
}
int main() {
memset(vis, 0, sizeof(vis));
//输入
for(int i = 0; i < 2 ; i++) {
for(int j = 0; j < 3; j++) {
char s = getchar();
if(s=='A') {
a.x=i; a.y=j; }
if(s=='B') {
b.x=i; b.y=j; }
if(s==' ') {
k.x=i; k.y=j; }
}
getchar();
}
//处理
dfs(a.x, a.y, b.x, b.y, k.x, k.y,0);
cout << Min << endl;
return 0;
}
这世界就是,一些人总在昼夜不停的努力,而另外一些人,起床就发现世界已经变了。 加油,陌生人!