歷屆試題 九宮重排 (bfs 八數碼問題)
阿新 • • 發佈:2019-02-18
問題描述
如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。
我們把第一個圖的局面記為:12345678.
把第二個圖的局面記為:123.46758
顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。
本題目的任務是已知九宮的初態和終態,求最少經過多少步的移動可以到達。如果無論多少步都無法到達,則輸出-1。 輸入格式 輸入第一行包含九宮的初態,第二行包含九宮的終態。 輸出格式 輸出最少的步數,如果不存在方案,則輸出-1。 樣例輸入 12345678.
123.46758 樣例輸出 3 樣例輸入 13524678.
46758123. 樣例輸出 22 這題困擾我很久 網站找了些八數碼的程式碼看看,什麼雜湊太深奧了,看不懂阿,後來找到了一段比較好理解的 程式碼:
我們把第一個圖的局面記為:12345678.
把第二個圖的局面記為:123.46758
顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。
本題目的任務是已知九宮的初態和終態,求最少經過多少步的移動可以到達。如果無論多少步都無法到達,則輸出-1。 輸入格式 輸入第一行包含九宮的初態,第二行包含九宮的終態。 輸出格式 輸出最少的步數,如果不存在方案,則輸出-1。 樣例輸入 12345678.
123.46758 樣例輸出 3 樣例輸入 13524678.
46758123. 樣例輸出 22 這題困擾我很久 網站找了些八數碼的程式碼看看,什麼雜湊太深奧了,看不懂阿,後來找到了一段比較好理解的 程式碼:
#include "iostream" #include "algorithm" #include "vector" #include "set" #include "string.h" #include "ctype.h" #define M 1000000 using namespace std; typedef int type[9]; type qs[M]; type mb; int front,rear; int dir[4][2]={-1,0,0,-1,0,1,1,0}; int dis[M]={0}; set<int> vis; //容器,儲存不同的值 int panchong(int x) { int i,sum=0; for (i=0; i<9; i++) { sum = sum*10+qs[x][i]; } if (vis.count(sum)) //容器中有相同 { return 0; } vis.insert(sum);//插入容器 return 1; } int bfs() { front = 1; rear = 2; int i,j,k=0,c,x,y,xx,yy; while (front < rear) { type &s = qs[front]; //s指向qs[front] if (memcmp(s,mb,sizeof(mb)) == 0) { return front; } for (k=0; k<9; k++) { if (s[k]==0) break; } x = k/3; y = k%3; // 轉成二維陣列 for (i=0; i<4; i++) { xx = x+dir[i][0]; yy = y+dir[i][1]; if(xx>=0 && xx<3 && yy>=0 && yy<3) { type &t = qs[rear];//t指向qs[rear] memcpy(t,s,sizeof(s)); t[k] = s[xx*3+yy]; //交換空格與數字位置 t[xx*3+yy] = s[k]; if (panchong(rear))//得到新的圖進行判斷重複 { dis[rear] = dis[front]+1; rear++; } } } front++; } return -1; } int main() { int i,j,cnt; char ch[10],ch2[10]; scanf("%s%s",ch,ch2); for (i=0; i<9; i++) { ch[i]<='8'&&ch[i]>='0' ? qs[1][i]=ch[i]-'0' : qs[1][i]=0; } for (i=0; i<9; i++) { ch2[i]<='8'&&ch2[i]>='0' ? mb[i]=ch2[i]-'0' : mb[i]=0; } cnt = bfs(); if(cnt>0) { cout<<dis[cnt]<<endl; } else { cout<<-1<<endl; } return 0; }