1. 程式人生 > >N皇后演算法—優化版

N皇后演算法—優化版

N皇后問題

【題目描述】 N皇后問題

         世界歷史上曾經出現一個偉大的羅馬共和時期,處於權力平衡的目的,當時的政治理論家波利比奧斯指出:“事涉每個人的權利,絕不應該讓任何權利大的壓過其它力量,使他人無法立足於平等條件與之抗辯的地步。”這類似著名的N皇后問題,即在NXN格的國際象棋上擺放N個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,請問有多少中擺法,並將每種擺法打印出來。圖1所示即是擺法的一種。

【輸入格式】

輸入一個整數,即N(14>N>3)。

【輸出格式】

輸出所有擺法,每個擺法佔一行

【輸入樣例】

4

【輸出格式】

2413

3142

【輸出說明】

N=4的棋盤輸出的兩種方案即圖2所示


遞迴演算法1

若想遍歷所有擺法而無一遺漏,可以逐行從上至下、從左至右嘗試棋子的擺放。以N=4的棋盤為例,其遍歷過程如圖3所示。


Tips:棋盤座標上一般會想到用二維陣列來表示,如定義二維陣列a[8][8],則a[0][0]=1代表棋盤第一行第一列有棋子,a[3][4]=0代表棋盤第4行第5列無棋子……但實際上只用一個一維陣列可以解決該問題。

            例如,使用a[8]來表示棋盤座標時,假設a[0]=7,即表示第1行第7列有棋子,a[1]=2即表示第2行第2列有棋子,而且這種方法無須再判斷兩皇后是否在同一行。

         可以定義一個Try(x,y)函式判斷棋盤(x,y)處是否可以放皇后:

(1)不在同一列

(2)不在對角線上,即有兩棋子座標分別為(X1,Y1),(X2,Y2),則|X1-X2|!=|Y1-Y2|

原始碼:
//N皇后問題——遞迴演算法
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int n,a[21];


void print()				//列印棋子 
{int i=1;
	for(;i<=n;i++)  
		cout<<a[i];
	cout<<" ";
		

		
	if(i%7==0)
		cout<<endl;
} 


void printGraph()			//圖形化列印佈局
{
	system("color F0");  	//DOs命令改變背景色和前景色,顏色為16進位制數0~F
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
			if(a[i] == j)
				cout<<"O";
			else
				cout<<"▅";
		cout<<endl;
	} 
	cout<<endl;
} 


int Try(int x,int y)			//測試x行y列可否擺放棋子,成功返回1,否則返回0 
{
	int j=1;
	while(j<x)					//與陣列中已放好的數比較 
	{
		if((a[j] == y) || (abs(x-j) == abs(a[j]-y)))
			return 0;
		++j;					//右移一格繼續嘗試 
	}
	return 1;
}

void place(int x)				//遞迴函式 
{
	int y;
	if(x>n)						//棋子第n行已擺好,則列印成功方案 
	{
		print();
		//printGraph();			//列印圖形化佈局 
	}
	else
	{
		for(y=1;y<=n;++y)		//該行棋子依次從左向右移 
			if(Try(x,y))		//如果可以擺放 
			{
				a[x]=y;			//給a[x]賦值 
				place(x+1);		//繼續下一行的遞迴 
			}
	}
}


int main()
{
	cin>>n;
	place(1);			//從第1行開始遞迴 
	return 0;
}

該程式中有個用於除錯的printGraph()函式,選用它可圖形化顯示佈局方案,如圖所示:


為了深入理解遞迴呼叫的過程,設N=4,則可將place(4)到place(4)的過程展開,如圖所示:


執行過程如圖下圖所示。

         模擬該程式執行過程時會發現,通過程式不斷的進進退退,最後就列印除了全部的佈局。

由此可知,遞迴中常常隱含回溯,回溯即選擇一條路走下去,發現走不通,就返回去再選一條路走。


以下為八皇后問題的解決,共92種擺法:


改程式當N>13時,速度將慢的難以忍受,並且考慮到輸出方案浪費了大量的時間,此後的優化演算法只需要輸出方案數即可。

遞迴演算法2

         以N=4為例,下圖左是正斜線,右是反斜線,即有2xN-1條、反斜線。


1號正斜線所佔據的棋盤單元為(1,1)

2號正斜線所佔據的棋盤單元為(1,2)(2,1)

3號正斜線所佔據的棋盤單元為(1,3)(2,2)(3,1)

4號正斜線所佔據的棋盤單元為(1,4)(2,3)(3,2)(4,1)

5號正斜線所佔據的棋盤單元為(2,4)(3,3)(4,2)

6號正斜線所佔據的棋盤單元為(3,4)(4,2)

7號正斜線所佔據的棋盤單元為(4,4)

可以發現規律如下:

(1)   同一正斜線所佔據的棋盤單元行列之和相等,如上面7條正斜線分別為2、3、4、5、6、7、8.

(2)   同一反斜線所佔據的棋盤單元行列之差相等。

故可以定義bool陣列x1[ ]用來記錄行列之和為i的正斜線是否已經被佔據,bool陣列x2[ ]用來記錄行列之差為i的反斜線是否已經被佔據。考慮到行列之差可能為負數,棋盤座標(x,y)對應x2[ x-y+n]。

再定義一個bool陣列y[ ]判斷列衝突,如果y[i]=1,說明前面已有皇后放到在這一列,再放會發生列衝突,y[i]=0,說明當前第i列還沒有放置皇后。
參考程式碼:
//N皇后——遞迴演算法2
#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

int n,num;

int a[20]={0};
bool y[41],x1[41],x2[41];


void place(int x)   					//遞迴函式
{
	if(x>n)
		++num;							//找到一個擺法,計數器加1 
	else
	{
		for(int i=1;i<=n;++i)
		{
			if(y[i] == 0 && x1[x+i] ==0 && x2[x-i+n] == 0)		//如果列,正斜線,反斜線無衝突 
			{
				a[x] = i;						//給a[x]賦值 
				y[i] = 1;						//列座標做標記 
				x1[x+i] = 1;					//正斜線做標記 
				x2[x-i+n] = 1;					//反斜線做標記 
				place(x+1);						//繼續下一行的遞迴 
				y[i] = 0;						//恢復 
				x1[x+i] = 0;					//恢復正斜線標記為0 
				x2[x-i+n] = 0;					//恢復反斜線標記為0 
			}
		}
	}
} 




int main()
{
	cin>>n;
	place(1);
	cout<<num<<endl;
}

優化後的程式提高了很多,但是當N>=14時候,速度還是較慢,我們還可以再次基礎上繼續優化,這裡我就不繼續寫了,希望大家能夠自己優化。


相關推薦

N皇后演算法優化

N皇后問題 【題目描述】 N皇后問題          世界歷史上曾經出現一個偉大的羅馬共和時期,處於權力平衡的目的,當時的政治理論家波利比奧斯指出:“事涉每個人的權利,絕不應該讓任何權利大的壓過其它力量,使他人無法立足於平等條件與之抗辯的地步。”這類似著名的N皇后問題,即

8皇后以及N皇后演算法探究,回溯演算法的JAVA實現,非遞迴,迴圈控制及其優化

研究了遞迴方法實現回溯,解決N皇后問題,下面我們來探討一下非遞迴方案 實驗結果令人還是有些失望,原來非遞迴方案的效能並不比遞迴方案效能高 程式碼如下: package com.newflypig.eightqueen; import java.util.Date; /**

8皇后以及N皇后演算法探究,回溯演算法的JAVA實現,非遞迴,資料結構“棧”實現

是使用遞迴方法實現回溯演算法的,在第一次使用二維矩陣的情況下,又做了一次改一維的優化 但是演算法效率仍然差強人意,因為使用遞迴函式的緣故 下面提供另一種回溯演算法的實現,使用資料結構”棧“來模擬,遞迴函式的手工實現,因為我們知道計算機在處理遞迴時的本質就是棧 時間複雜度是一樣的,空間

8皇后以及N皇后演算法探究,回溯演算法的JAVA實現,遞迴方案(一)

八皇后問題,是一個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。 高斯認為有76種方案。1854年在柏林的象棋雜誌

8皇后以及N皇后演算法探究,回溯演算法的JAVASCRIPT實現,遞迴方案

java原文參考這位大神,他的部落格中有關於N皇后問題的極限演算法 我只是搬運翻譯的js實現  console.log使用node.js到時候替換即可。 //定義陣列克隆方法 Array.prototype.clone = function(){     var a=

皇后問題優化(含程式碼)

之前發表過一個版本的八皇后,後來在洛谷上看到了另一個八皇后(其實是N皇后)。這個最大到達13,對剪枝要求較高。之前版本的程式有一個測試點無法通過。 提供參考程式碼: #include #inclu

演算法筆記_全排列與N皇后問題

說明:這裡的全排列是按字典序的. 以下給出從1到3的全排列程式碼: #include<iostream> #include<stdlib.h> using namespace std; const int maxn = 11; //P為當前排列,hashTable記錄

PHP使用演算法求出最大同花順(優化2.0)

PHP使用演算法求出最大同花順(優化版2.0) <?php // $poker[0] 撲克牌花色 1~4 代表黑桃 黑桃 梅花 方塊 // $poker[1] 撲克牌數字 1~13 代表1~10 J Q K $poker = array ( 0 => arr

N皇后問題(搜尋C語言

用陣列int x[N]表示棋盤狀態,例如x[0]=1表示第0行皇后放在第1列。 皇后k在第k行第x[k]列:(k,x[k]) 測試方法:測試皇后k在第k行第x[k]列時,是否與前面已放置好的皇后j相攻擊。 x[j]== x[k] 時,兩皇后在同一列上; abs(k-j)==abs(x[j]-

【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現

N皇后問題 問題描述 在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法,這稱為八皇后問題。 延伸一下,便為N皇后問題。 核心思想 解決N皇后問題有兩個關鍵點。一是如何進行放置棋子,二是如何驗證棋子是否符合

Leetcode演算法——51~52、n皇后問題

n皇后問題需要將n個皇后放置在n*n的棋盤上,保證任意兩個皇后都不能處於同一行、同一列或同一斜線上。 51、給定一個整數n,返回n皇后問題的所有不重複的解。 51、給定一個整數n,返回n皇后問題的所有不重複的解的個數。 每個解都是一種n個皇后的佈局,其中 ‘Q’ 和 ‘.’ 分別

演算法-N皇后問題

2018/9/23 N皇后問題:在NxN的棋盤上,放置N個棋子, 使得同一行、同一列、同一對角線上只有一個棋子,問有多少種滿足條件的放置方法?         回溯法和位運演算法 方法1: 【回溯法】 回溯法也叫試探法,她是一種系統地搜尋問題的解的方法。   

人工智慧實驗——隨機重啟爬山法,模擬退火演算法,遺傳演算法求解N皇后問題

一、爬山法 爬山法就是完全的貪心演算法,每一步都選最優位置,可能只能得到區域性最優解。本實驗對普通爬山法進行了簡單的優化,採用了傳統爬山法的變種——隨機重啟爬山法,當爬山步數超過一定值時,會重新打亂棋盤,重新“爬山”。 適應度函式:衝突皇后的總對數 “爬山”:每一步就是

n皇后概率演算法與確定演算法折衷考慮最後解法

#include "pch.h" #include <iostream> #include <vector> #include <random> #include <ctime> #include <time.h>

演算法作業——八皇后問題擴充套件到N皇后

問題背景:在 8×8 格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,輸出所有擺法。 環境:VS2017 程式碼: #include "pch.h" #include <iostream> #include

N皇后 遞迴演算法

int n; int queenpos[100];     //用來存放算好的皇后位置。最左上角是(0.0)  void nqueen (int k);   int main() {     cin >> n;          nqueen(0);     

演算法優化:動態規劃加速,貨物運輸問題,四邊形不等式, 從O(n^2)到O(n^3)

貨物運輸問題 遞迴方程為: 更為一般形式的遞迴方程 看起來是不是像可以使用分治的策略實現,但是min裡面子問題太多了,只能使用動態規劃的招了。 i,j是什麼含義了?動態規劃裡i,j都是指的是問題規模,對應到貨物運輸問題指的是什麼了?我們從數學上理解i,j是指

演算法優化:最大欄位和,雙指標遍歷(n^2),分治法(nlogn),動態規劃(n)

最大欄位和,有點類似與最長公共子序列,這裡是求連續一段求和最大的一段,比如[-2,11,-4,-4,13,-5,-2]最大求和的連續一段為11,-4,-4,13,和為16. 最基本的雙針模型遍歷,兩個指標,分別代表最大和序列的起始和終止,演算法時間複雜度O(n^2) # 以下演算法時

演算法n皇后問題

1. 問題描述:在n×n的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n皇后問題等價於在n×n的棋盤上放置n個皇后,任何2個皇后不能放在同一行或同一列或同一斜線上。 2. 問題分析: 用n元陣列x[n]表示

n皇后(位運算

其實我也沒覺得多快233333333 #include <cstdio> #include <iostream> #include <algorithm> #i