BFS-八數碼問題與狀態圖搜索

  在一個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)檢查座標是否合法   

八數碼問題多種解法:http://www.javashuo.com/article/p-yfxanbbg-g.html

相關文章
相關標籤/搜索