八數碼問題

2022-08-22 13:09:11 字數 1923 閱讀 3798

任務1:指定初始棋局和目標棋局,計算出最少的移動步數;

任務2:輸出數碼的移動序列;

把空格看成0,一共9個數字。

1 2 3 0 8 4 7 6 5

1 0 3 8 2 4 7 6 5

[解析:]

這裡有兩個巧妙的地方,乙個是將棋局看作乙個狀態圖,那麼總共有

\(9!= 362880\)個狀態,從初始棋盤開始,每次移動到下乙個狀態,到達目標棋局後終止;

八數碼問題是乙個經典的bfs問題,從起始位置開始由內向外擴散開來,從而逼近目標,當到達目標時就是步數最短路徑。其實bfs也用在權值一樣的求最短路徑問題中,當然用圖也可以搞定,這就是後話了。

回到本題來,在進行bfs遍歷時會遍歷許多重複的狀態,如果不去重那麼程式會產生很多無效操作,另外乙個巧妙的地方使用快速判重方式。如果在這裡採用暴力去重,那麼需要將新狀態與\(9!\)個狀態比較,會產生\(9!x9!\)次判斷,明顯不行。

這裡介紹乙個數學方法:康托展開(cantor expansion)來去重;

說白了,cantor去重實際是乙個特殊hash函式:

狀態012345678

012345687

012345768

...876543210

cantor01

2...

362880-1

cantor()的複雜度為o(\(n^2\)),n是集合中元素的個數,因此本題中完成搜尋和判重的總複雜度為o(\(n!n^2\)),遠比暴力解o(\(n!n!\))小。

下面介紹康托的原理:

例子:判斷2143是中全排列中第幾大數;

計算在2143前面的排列數目,可轉換為一下排列和:

1)首位小於2的排列:這裡比2小的就只有1,因此後面3位排列為\(3!=6\);可寫成\(1x3!=6\)

2)首位為2,第二位小於1的數列:沒有,亦可寫成\(0x2!=0\)

3)前兩位為21,第三位小於4的所有排列:只有3乙個, \(1x1!=1\)

4)前3位位214,第4位小於3的所有排列:無,寫為\(0x0!=0\)

把乙個集合產生的全排列按照字典序排序,第x個排列的計算公式為:

\(x = a[n]x(n-1)! + a[n-1]x(n-2)! + ... + a[i]x(i-1)! + ... + a[2]x1! + a[1]x0!\)

其中a[i]表示原數的第i位在當前未出現的元素中排在第幾個(從0開始),且有\(0 \leq a[i] < i (1 \leq i \leq n)\)

上面去重是cantor的逆展開:某個集合的全排列,輸入數字k,返回第k大的排列;

#include const int len = 362880; //總狀態數9!=362880;

using namespace std;

struct node

;int dir[4][2] = ,,,

,};int visited[len] = ;

int start[9]; //起始狀態;

int target[9]; //目標狀態;

//階乘計算結果預存;

long int factory = ;

bool cantor(int str, int n)

res += counter * factory[n - i - 1];

}if (!visited[res])

return false;

}int bfs()

int x = z % 3;

int y = z / 3;

for (int i = 0; i < 4; i++)

if (cantor(newnode.state, 9))

qu.push(newnode);}}

}return -1;

}int main()

下面是oj的兩題,可以切一下

八數碼問題

八數碼問題 一.八數碼問題 八數碼問題也稱為九宮問題。在3 3的棋盤,擺有八個棋子,每個棋子上標有1至8的某一數字,不同棋子上標的數字不相同。棋盤上還有乙個空格,與空格相鄰的棋子可以移到空格中。要求解決的問題是 給出乙個初始狀態和乙個目標狀態,找出一種從初始轉變成目標狀態的移動棋子步數最少的移動步驟...

八數碼問題

2 6 4 1 3 7 0 5 8 8 1 5 7 3 6 4 0 2 樣例輸出 還有就是重判的問題,如何重判呢?第一種方法 把排列變成整數,然後只開乙個一維陣列,也就是說設計一套排列的編碼和解碼函式,把0 8的全排列和0 362879的整數意義一一對應起來。時間效率高,但編碼解碼法適用範圍並不大,...

八數碼問題

八數碼問題 題意 編號為1 8的8個正方形滑塊被擺成3行3列 有乙個格仔留空 如下圖所示 每次可以把與空格相鄰的滑塊 有公共邊才算相鄰 移到空格中,而他原來的位置 就成為了新的空格。如果無法到達目標局面,則輸出 1。2 6 4 13 75 8 移到後 8 1 5 73 642 樣例輸入 2 6 4 ...