題目鏈接: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; }