n皇后問題 [隨機化算法,拉斯維加斯算法]


問題:

  如何能夠在 n×n 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。

分析:

  這題常規的解法應該是回溯法,然而回溯法的話,要遍歷所有的情況。

  這里介紹一種隨機化的算法:

  我們先擺開頭的幾個棋子,然后剩下的棋子用回溯法來做,由於解空間樹的頭幾層不用拿來遍歷了,回溯的時候遍歷的結點少了很多。

  研究標明,隨機擺開頭的一半略少的棋子,可以很快得得到解。當然,這個算法是只能求出一部分的解的,但是在 n 很大的時候速度比回溯法快了非常多。

  ps:回溯法是可以得到所有解的。

做法:

  先隨機擺頭幾個棋子,這里有一個很棒的算法,參考:http://blog.csdn.net/yusiguyuan/article/details/42607681

  但是為了方便,我這里的做法是對一個數組中的所有元素做幾次隨機的交換。  

void randomPlace(int n, int pieces[]) {//隨機擺放棋子
 srand((unsigned)time(NULL)); for (int i = 0; i < n; i++) { int a = random(n) + 1; int b = random(n) + 1; swap(pieces[a], pieces[b]); } }

  然后對接下來的棋子用回溯法:  

void nQueen(int n, int t, int pieces[]) {//回溯法解n后問題
    if (t > n) { resultNumber++;//計算解的個數
        for (int i = 1; i <= n; i++) { for (int j = 1; j < pieces[i]; j++) cout << "- "; cout << pieces[i] << " "; for (int j = pieces[i] + 1; j <= n; j++) cout << "- "; cout << endl; } cout << endl; } else { for (int i = t; i <= n; i++) { swap(pieces[t], pieces[i]); if (isOK(t, pieces)) { nQueen(n, t + 1, pieces); } swap(pieces[t], pieces[i]); } } }

  這兩個函數應該在LasVegas函數中調用,知道得出至少一個解:  

void LasVegas(int n, int pieces[]) {//拉斯維加斯算法: //先隨機擺前面的一些棋子,然后后面的用回溯法來解
    if (n == 1) {//特殊情況
        cout << 1 << endl; } else { for (int i = 1; i <= n; i++) { pieces[i] = i; } while (resultNumber == 0) { //前幾個擺的也要合理才行
            while (!isOK(n / 2, pieces)) { randomPlace(n, pieces); } nQueen(n, (n / 2)-1, pieces);//隨機一半略少的棋子擺放
 } } }

  代碼是從 n皇后問題改過來的,其中部分代碼我這里就不顯示出來了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM