問題 J: 八數碼問題
時間限制: 5 Sec 內存限制: 128 MB提交: 143 解決: 80
[提交][狀態][討論版]
題目描述
八數碼問題,即在一個3×3的矩陣中有8個數(1至8)和一個空格,現在要你從一個狀態轉換到另一個狀態,每次只能移動與空格相鄰的一個數字到空格當中,問題是要你求從初始狀態移動到目標狀態所需的最少步數。如下圖所示。
1 |
2 |
3 |
|
1 |
2 |
3 |
8 |
0 |
4 |
|
7 |
8 |
4 |
7 |
6 |
5 |
|
0 |
6 |
5 |
初始狀態 目標狀態
如上圖所示的數據以矩陣形式給出。現在給出分別代表初始狀態和目標狀態的兩個3*3的矩陣,請給出兩個矩陣相互轉化的最少步數。
輸入
第1行-第3行:3個用空格分隔的整數,代表初始狀態相應位置的數字,0代表空格
第4行-第6行:3個用空格分隔的整數,代表終止狀態相應位置的數字,0代表空格
輸出
第1行:一個整數,最小轉換步數,如不能到相互轉化則輸出"Impossible"
樣例輸入
1 2 3
8 0 4
7 6 5
1 2 3
7 8 4
0 6 5
樣例輸出
2
提示
#include <iostream>
#include <queue>
#include <cstdio>
#include <set>
#include <cstring>
using namespace std;
typedef int state[9];
state st[1000010],end1; //st相當於二維數組
int dis[1000010];
set <int> ly; //set維護st
void table() {
ly.clear();
}
int try_insert(int a) {
int s=0;
for(int j=0; j<9; j++)
s=s*10+st[a][j];
if(ly.count(s)) return 0; //利用stl去重,是最容易實現的
ly.insert(s);
return 1;
}
const int dir[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
int bfs() {
table();
int fr=1,re=2;
while(fr<re) {
state& s =st[fr];
if(!memcmp(s,end1,sizeof(s))) return fr;
int z;
for(z=0; z<9; z++) if(!s[z]) break;
int x=z/3; //轉爲二維空間的行
int y=z%3; // 轉爲二維空間的列
for(int i=0; i<4; i++) {
int newx=x+dir[i][0];
int newy=y+dir[i][1];
int newz=newx*3+newy;
if(newx>=0 && newx <3 && newy>=0 && newy<3) {
state &t=st[re];
memcpy(t,s,sizeof(t));
t[newz]=s[z];
t[z]=s[newz];
dis[re]=dis[fr]+1;
if(try_insert(re)) re++; //如果沒有重複出現,尾指針re向後移位。如果重複,則仍停在原來的位置。
}
}
fr++;
}
return 0;
}
int main() {
int ans=0;
for(int i=0; i<9; i++) {
scanf("%d",&st[1][i]);
}
for(int i=0; i<9; i++) {
scanf("%d",&end1[i]); //最終目標
}
ans=bfs();
if(ans>0) printf("%d\n",dis[ans]);
else
printf("Impossible\n");
}