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