n後問題2.0(拉斯維加斯隨機算法)

前言:

昨天總結了個傳統窮舉的回溯法,考慮到由於遞歸回溯法時間複雜度高,超過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忘記初始化,以致於運行代碼遲遲發現問題卻無從下手,小坑呵.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章