在一個3*3的棋盤上放置編號爲1~8的八個方塊,每一個佔一格,另外還有一個空格。與空格相鄰的數字方塊能夠移動到空格里。任務1:指定的初始棋局和目標棋局,計算出最少的移動步數;任務2:數出數碼的移動序列。html
把空格當作0,一共有九個數字。node
輸入樣例:c++
1 2 3 0 8 4 7 6 5 數組
1 0 3 8 2 3 7 6 5 函數
輸出樣例:spa
2code
1.把一個棋局當作一個狀態圖,總共有9!= 362880個狀態。從初始棋局開始,每次移動轉到下一個狀態,達到目標棋局後中止。htm
2.康託展開blog
康託展開是一種特殊的哈希函數。其功能是在輸入一個排列,計算出它在在全排列中從小到大排序的位次。排序
eg:判斷 2143是{1,2,3,4}的全排列中的位次。
(1)首位小於2的全部排列。比2小的只有1,後面三個數的排列有3*2*1=3!個,寫成1*3!=6
(2)首位爲2,第二位小於1的全部排列。無,寫成0*2!=0
(3)前兩位爲21,第三位小於4的全部排列。只有3一個數,寫成1*1!=1
(3)前三位爲214,第四位小於3的全部排列。無,寫成0*0!=0
求和:1*3!+0*2!+1*1!+0*0!=7
因此位次的計算公式爲X = a[n]*(n-1)! +a[n-1]*(n-2)! + … + a[1]*0!
1 #include<bits/stdc++.h> 2 #include<queue> 3 using namespace std; 4 5 const int len = 362880; //狀態共9! = 362880種 6 int visited[len] = {0};//標記已有狀態用來去重 7 int start[9];//起始狀態 8 int goal[9];//目標狀態 9 int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362800};//0到9的階乘 10 int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; 11 12 struct node{ 13 int state[9];//棋局狀態按一維存放下來 14 int dis;//記錄從起始狀態移動到當前狀態的步數 15 }; 16 17 bool cantor(int str[], int n){ 18 int result = 0; 19 for(int i=0; i<n; i++){ 20 int cnt = 0; 21 for(int j=i+1; j<n; j++){ 22 if(str[i] > str[j]) 23 cnt ++; 24 } 25 result += cnt+factory[n-i-1]; 26 } 27 if(!visited[result]){ 28 visited[result] = 1; 29 return 1; 30 } 31 return 0; 32 } 33 34 int BFS(){ 35 node head, next; 36 memcpy(head.state, start, sizeof(head.state));//複製起始狀態並插入隊列 37 head.dis = 0; 38 cantor(head.state, 9); 39 queue<node>q; 40 q.push(head); 41 42 while(!q.empty()){ 43 head = q.front(); 44 q.pop(); 45 int z; 46 for(z=0; z<9; z++) 47 if(head.state[z] == 0)//找到0 48 break; 49 int x = z % 3;//將0的一維位置轉化爲二維的橫縱座標 50 int y = z / 3; 51 for(int i=0; i<9; i++){ 52 int newx = x + dir[i][0]; 53 int newy = y + dir[i][1]; 54 int newz = newx + 3*newy;//將0移動後從新轉化爲一維座標 55 if(newx>=0 && newx<3 && newy>=0 && newy<3){//避免越界 56 memcpy(&next, &head, sizeof(struct node)); 57 swap(next.state[z], next.state[newz]);//複製原先狀態後,改變0的位置 58 next.dis ++; 59 if(memcmp(next.state, goal, sizeof(next.state)) == 0) 60 return next.dis; 61 if(cantor(next.state, 9))//查重 62 q.push(next); 63 } 64 } 65 } 66 return -1; 67 } 68 69 int main(){ 70 for(int i=0; i<9; i++) 71 scanf("%d", start+i); 72 for(int i=0; i<9; i++) 73 scanf("%d", goal+i); 74 75 int num = BFS(); 76 if(num != -1) 77 printf("%d\n",num); 78 else 79 printf("Impossible\n"); 80 }
(1)用於存放狀態圖的以及步數的結構體
(2)用於移動的數組
(3)用於去重的標記數組
(4)提早算好階乘存放於數組中
(5)康拓函數判重
(6)BFS函數:queue<node>q;node head, next;
(7)狀態圖中某數字方塊的一維座標和二維座標的相互轉化
(8)檢查座標是否合法