前言:
昨天總結了個傳統窮舉的回溯法,考慮到由於遞歸回溯法時間複雜度高,超過12的皇后計算代價太大.如果基數過大,回溯法的優勢就不明顯了.
所以關於該算法的改進還有另一種拉斯維加斯(Las Vegas)算法,結合了隨機函數,提高了效率.
一.源程序:
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<stdio.h>
using namespace std;
class Queen
{
friend void nQueen(int i);
private:
bool Place(int k);
bool QueensLV(void);
int n;
int *x,*y;
};
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; //注意這裏不是else執行返回true,當每一行都測試過沒有衝突之後才返回true
}
bool Queen::QueensLV(void) //定義私有成員函數,實現逐行隨機擺放
{
int k = 1,count = 1;
while((k<=n)&&(count>0))
{
count=0;
for (int i = 1; i <=n; i++)
{//從第一列到第n列 對第k行的皇后逐個試探,若合法則記錄與y數組,並且累加解決方案count
x[k] = i;
if(Place(k))
{y[count]=i; count++; }
}
if(count>0)
{
int z = rand()%count; //產生從0 ~ (count-1)的隨機數,即在解決方案數組y中隨機找一個作爲該行放置位置
x[k]=y[z]; k++; //在記錄的方案中隨機放置,並且k++進入下一行
}
}
return (count>0); //若執行到該行,則表示while循環結束,表明所有行皆走過,此時若解決方案存在,則有解.
}
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]; //注意要給x和y數組初始化
while (!X.QueensLV()); //注意QueensLV函數一旦發現無法再放置下一個皇后,需要重新開始不斷重複調用QueensLv, //直到找到解決方案<pre name="code" class="cpp"> //不足之處若該n後無解,仍然繼續死循環.
for (int i = 1; i <=n; i++)
{cout<<p[i]<<" ";}
cout<<endl;
delete[]p;
}
int main()
{
int N;//皇后個數,解決方案;
int t=4;
while(t--)
{
cout<<"請輸入皇后個數:"<<endl;
cin>>N;
nQueen(N);
}
}
二.結果示例:
三.小結
由於該隨機算法只是找出解決方案的一個即返回,若方案有多個,則隨機選取.所以執行同樣個數的n後問題可能有不同的解.
然而該算法還是有缺陷,比如每次放置皇后到一定行數,如果發現沒有再可以放置的話就從又要重新再來.
明天接着折騰另一個改進的版本 隨機算法結合回溯法的n後問題.
參考資料:《計算機算法設計與分析》 p222
Ps:注意書上例子有個問題 ,數組y忘記初始化,以致於運行代碼遲遲發現問題卻無從下手,小坑呵.