[蓝桥杯2016初赛]卡片换位
题目链接:http://oj.ecustacm.cn/problem.php?id=1296
题目描述
你玩过华容道的游戏吗?这是个类似的,但更简单的游戏。看下面 3 x 2 的格子
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
+---+---+---+ | A | * | * | +---+---+---+ | B | | * | +---+---+---+在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
输入
输入存在多组测试数据,对于每组测试数据:
输入两行6个字符表示当前的局面
输入两行6个字符表示当前的局面
输出
对于每组测试数据输出一个整数表示答案
样例输入 Copy
* A
**B
A B
***
样例输出 Copy
17
12
思路:
题目问最少需要几次,那么很容易想到利用 BFS 去求解
但是这道题相当于一个图的遍历,隐式图的遍历要注意去重的问题,这也是这道题的一个难点。
这里采用开一个数组 去记录 A B 空格三个的位置(因为它要求其他的无所谓),这样就可以完成去重的任务了
然后我们每次都从空格开始走,和普通的 BFS 是一样的
#include <iostream> #include <algorithm> #include <string> #include <string.h> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <math.h> #include <cstdio> #include <iomanip> #include <time.h> #define LL long long #define INF 0x3f3f3f3f #define ls nod<<1 #define rs (nod<<1)+1 const int maxn = 1e5 + 10 ; const LL mod = 20010905; char map[10][10]; int row_a,row_b,col_a,col_b,row,col; int dir[4][2] = {0,1,0,-1,1,0,-1,0}; int vis[3][3][3][3][3][3]; struct Node { int r,c; int ar,ac; int br,bc; int step; }; void bfs() { std::queue<Node> q; Node now; now.r = row; now.c = col; now.ar = row_a,now.ac = col_a; now.br = row_b,now.bc = col_b; now.step = 0; q.push(now); while (!q.empty()) { now = q.front(); q.pop(); if (vis[now.ar][now.ac][now.br][now.bc][now.r][now.c]) continue; vis[now.ar][now.ac][now.br][now.bc][now.r][now.c] = 1; if (now.ar == row_b && now.ac == col_b && now.br == row_a && now.bc == col_a ) { printf("%d\n",now.step); return ; } for (int i = 0;i < 4;i++) { int x = now.r + dir[i][0]; int y = now.c + dir[i][1]; if (x < 0 || x > 1 || y < 0 || y > 2) continue; Node ed = now; ed.r = x,ed.c = y; ed.step++; if (x == now.ar && y == now.ac) { ed.ac = now.c; ed.ar = now.r; } if (x == now.br && y == now.bc) { ed.bc = now.c; ed.br = now.r; } if (vis[ed.ar][ed.ac][ed.br][ed.bc][ed.r][ed.c]) continue; q.push(ed); } } } int main() { while (gets(map[0]) != NULL ) { gets(map[1]); memset(vis,0, sizeof(vis)); for (int i = 0; i <= 1; i++) { for (int j = 0; j <= 2; j++) { if (map[i][j] == ' ') { row = i; col = j; } if (map[i][j] == 'A') { row_a = i; col_a = j; } if (map[i][j] == 'B') { row_b = i; col_b = j; } } } bfs(); } return 0; }
还有一种 DFS 的写法,大致的想法也是差不多的
#include <iostream> #include <algorithm> #include <string> #include <string.h> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <math.h> #include <cstdio> #include <iomanip> #include <time.h> using namespace std; #define inf 0x3f3f3f3f int minn=inf; using namespace std; int go[4][2]= {0,1,0,-1,1,0,-1,0};//方向向量 int vis[3][3][3][3][3][3];//标记数组 struct node { int x; int y; } a,b,k;//分别记录a,b和空格的坐标 void input()//处理输入 { char s; while((s=getchar())!=EOF){ for(int i=0; i<2; i++) { for(int j=0; j<3; j++) { s=getchar(); if(s==' ') { k.x=i; k.y=j; } if(s=='A') { a.x=i; a.y=j; } if(s=='B') { b.x=i; b.y=j; } } getchar(); } } } void dfs(int x1,int y1,int x2,int y2,int x,int y,int step) { if(step>minn) return; if(x1==b.x&&y1==b.y&&x2==a.x&&y2==a.y)//x1y1到达b x2y2到达a 难道xy是空格? { minn=step; return; } //判断越界 if(x<0||x>1||y<0||y>2) return; if(x1<0||x1>1||y1<0||y1>2) return; if(x2<0||x2>1||y2<0||y2>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 xx=x+go[i][0]; int yy=y+go[i][1]; if(xx==x1&&yy==y1)//新的一步走到了A处 dfs(x,y,x2,y2,x1,y1,step+1);//int x1,int y1,int x2,int y2,int x,int y,int step 走到A处,xy和A直接交换位置带入 else if(xx==x2&&yy==y2) dfs(x1,y1,x,y,x2,y2,step+1);//走到B处,xy和B交换带入 else dfs(x1,y1,x2,y2,xx,yy,step+1);//和AB无关则,空格位置改变 } vis[x1][y1][x2][y2][x][y]=0; } int main() { char s; while((s=getchar())!=EOF) { if (s == ' ') { k.x = 0; k.y = 0; } if (s == 'A') { a.x = 0; a.y = 0; } if (s == 'B') { b.x = 0; b.y = 0; } for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { if (i == 0 && j == 0) continue; s = getchar(); if (s == ' ') { k.x = i; k.y = j; } if (s == 'A') { a.x = i; a.y = j; } if (s == 'B') { b.x = i; b.y = j; } } getchar(); } minn=inf; memset(vis,0, sizeof(vis)); dfs(a.x, a.y, b.x, b.y, k.x, k.y, 0); printf("%d\n", minn); } return 0; }