1、拉斯維加斯(Las Vegas)算法
舍伍德算法優點在於計算時間復雜度對所有實例相對均勻,但與其相應的確定性算法相比,其平均時間復雜度沒有改進。拉斯維加斯算法則不然,它能顯著改進算法的有效性,甚至對某些迄今為止找不到有效算法的問題,也能得到滿意的算法。
拉斯維加斯算法不會得到不正確的解。一旦用拉斯維加斯算法找到一個解,這個解就一定是正確解。但有時用拉斯維加斯算法找不到解。與蒙特卡羅算法類似,拉斯維加斯算法找到正確解的概率隨着它所用的計算時間的增加而提高。對於所求解問題的任一實例,用同一拉斯維加斯算法反復對該實例求解足夠多次,可使求解失敗的概率任意小。拉斯維加斯算法的一個顯著特征是它所作的隨機性決策有可能導致算法找不到所需的解。

void obstinate(Object x, Object y) {// 反復調用拉斯維加斯算法LV(x,y),直到找到問題的一個解y bool success= false; while (!success) success=lv(x,y); }
設p(x)是對輸入x調用拉斯維加斯算法獲得問題的一個解的概率。一個正確的拉斯維加斯算法應該對所有輸入x均有p(x)>0。設t(x)是算法obstinate找到具體實例x的一個解所需的平均時間 ,s(x)和e(x)分別是算法對於具體實例x求解成功或求解失敗所需的平均時間,則有。解此方程得:
2、n后問題
問題描速:在n×n格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n后問題等價於在n×n格的棋盤上放置n個皇后,任何2個皇后不放在同一行或同一列或同一斜線上。
1)純拉斯維加斯隨機算法求解思路
對於n后問題的任何一個解而言,每一個皇后在棋盤上的位置無任何規律,不具有系統性,而更象是隨機放置的,由此想到拉斯維加斯算法。在棋盤上相繼的各行中隨機地放置皇后,並注意使新放置的皇后與已放置的皇后互不攻擊,直至n個皇后均已相容地放置好,或已沒有下一個皇后的可放置位置時為止。
具體實現代碼如下:

//隨機化算法 拉斯維加斯算法 n后問題 #include "stdafx.h" #include "RandomNumber.h" #include <cmath> #include <iostream> using namespace std; class Queen { friend void nQueen(int); private: bool Place(int k); //測試皇后k置於第x[k]列的合法性 bool QueensLv(void); //隨機放置n個皇后拉斯維加斯算法 int n; //皇后個數 int *x,*y; //解向量 }; //測試皇后k置於第x[k]列的合法性 bool Queen::Place(int k) { for(int j=1; j<k; j++) { if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) { return false; } } return true; } //隨機放置n個皇后的拉斯維加斯算法 bool Queen::QueensLv(void) { RandomNumber rnd; //隨機數產生器 int k = 1; //下一個皇后的編號 int count = 1; //在一列中,可以放置皇后的個數 while((k<=n)&&(count>0)) { count = 0; for(int i=1; i<=n; i++) { x[k] = i;//位置 if(Place(k)) { y[count++] = i; } } if(count>0) { x[k++] = y[rnd.Random(count)]; //隨機位置 } } return (count>0); //count>0 表示放置成功 } //解n后問題的拉斯維加斯算法 void nQueen(int n) { Queen X; X.n = n; int *p = new int[n+1]; for(int i=0; i<=n; i++) { p[i] = 0; } X.x = p; X.y = new int[n+1]; //反復調用隨機放置n個皇后的拉斯維加斯算法,直到放置成功 while(!X.QueensLv()); for(int i=1; i<=n; i++) { cout<<p[i]<<" "; } cout<<endl; delete []p; } int main() { int n=8; cout<<n<<"皇后問題的解為:"<<endl; nQueen(n); return 0; }

#include"time.h" //隨機數類 const unsigned long maxshort = 65536L; const unsigned long multiplier = 1194211693L; const unsigned long adder = 12345L; class RandomNumber { private: //當前種子 unsigned long randSeed; public: RandomNumber(unsigned long s = 0);//構造函數,默認值0表示由系統自動產生種子 unsigned short Random(unsigned long n);//產生0:n-1之間的隨機整數 double fRandom(void);//產生[0,1)之間的隨機實數 }; RandomNumber::RandomNumber(unsigned long s)//產生種子 { if(s == 0) { randSeed = time(0);//用系統時間產生種子 } else { randSeed = s;//由用戶提供種子 } } unsigned short RandomNumber::Random(unsigned long n)//產生0:n-1之間的隨機整數 { randSeed = multiplier * randSeed + adder;//線性同余式 return (unsigned short)((randSeed>>16)%n); } double RandomNumber::fRandom(void)//產生[0,1)之間的隨機實數 { return Random(maxshort)/double(maxshort); }
代碼實現結果:
上述算法一旦發現無法再放置下一個皇后,就全部重新開始,下面是將隨機放置策略與回溯法結合例子。

//隨機化算法 拉斯維加斯算法 n后問題 #include "stdafx.h" #include "RandomNumber.h" #include <cmath> #include <iostream> using namespace std; class Queen { friend bool nQueen(int); private: bool Place(int k); //測試皇后k置於第x[k]的合法性 bool Backtrack(int t); //解n后問題的回溯法 bool QueensLV(int stopVegas); //隨機放置n個皇后拉斯維加斯算法 int n,*x,*y; }; //測試皇后k置於第x[k]列的合法性 bool Queen::Place(int k) { for(int j=1; j<k; j++) { if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) { return false; } } return true; } //解n后問題的回溯法 bool Queen::Backtrack(int t) { if(t>n) { for(int i=1; i<=n; i++) { y[i] = x[i];//問題的解 } return true; } else { for(int i=1; i<=n; i++) { x[t] = i; if(Place(t)&&Backtrack(t+1)) { return true; } } } return false; } //隨機放置n個皇后拉斯維加斯算法 bool Queen::QueensLV(int stopVegas) { RandomNumber rnd; //隨機數產生器 int k = 1; int count = 1; //1<=stopVegas<=n while((k<=stopVegas)&&(count>0)) { count = 0; for(int i=1; i<=n; i++) { x[k] = i; if(Place(k)) { y[count++] = i; } } if(count>0) { x[k++] = y[rnd.Random(count)];//隨機位置 } } return (count>0); //count>0表示放置成功 } //與回溯法相結合的解n后問題的拉斯維加斯算法 bool nQueen(int n) { Queen X; //初始化X X.n = n; int *p = new int[n+1]; int *q = new int[n+1]; for(int i=0; i<=n; i++) { p[i] = 0; q[i] = 0; } X.y = p; X.x = q; int stop = 3; if(n>15) { stop = n-15; } bool found = false; while(!X.QueensLV(stop)); //算法的回溯搜索部分 if(X.Backtrack(stop+1)) { for(int i=1; i<=n; i++) { cout<<p[i]<<" "; } found = true; cout<<endl; } delete []p; delete []q; return found; } int main() { int n=8; cout<<n<<"皇后問題的解為:"<<endl; while(!nQueen(n)); return 0; }

#include"time.h" //隨機數類 const unsigned long maxshort = 65536L; const unsigned long multiplier = 1194211693L; const unsigned long adder = 12345L; class RandomNumber { private: //當前種子 unsigned long randSeed; public: RandomNumber(unsigned long s = 0);//構造函數,默認值0表示由系統自動產生種子 unsigned short Random(unsigned long n);//產生0:n-1之間的隨機整數 double fRandom(void);//產生[0,1)之間的隨機實數 }; RandomNumber::RandomNumber(unsigned long s)//產生種子 { if(s == 0) { randSeed = time(0);//用系統時間產生種子 } else { randSeed = s;//由用戶提供種子 } } unsigned short RandomNumber::Random(unsigned long n)//產生0:n-1之間的隨機整數 { randSeed = multiplier * randSeed + adder;//線性同余式 return (unsigned short)((randSeed>>16)%n); } double RandomNumber::fRandom(void)//產生[0,1)之間的隨機實數 { return Random(maxshort)/double(maxshort); }
運行結果:
參考文獻:王曉東《算法設計與分析》第二版