1. 程式人生 > >目前解決N皇后遞迴問題最快辦法(位操作)

目前解決N皇后遞迴問題最快辦法(位操作)

也是使用遞迴+回溯的辦法:只不過使用了位運算代替陣列,使得效率更高

其核心程式碼:

// 試探演算法從最右邊的列開始。
void test(long col, long ld, long rd)
{
    if (col != upperlim){
        // row,ld,rd進行“或”運算,求得所有可以放置皇后的列,對應位為0,
        // 然後再取反後“與”上全1的數,來求得當前所有可以放置皇后的位置,對應列改為1
        // 也就是求取當前哪些列可以放置皇后
        long pos = upperlim & ~(col | ld | rd);
        while (pos){
            // 拷貝pos最右邊為1的bit,其餘bit置0
            // 也就是取得可以放皇后的最右邊的列
            long p = pos & -pos;//類似樹狀陣列中操作,取一個數二進位制的最後一個1

            // 將pos最右邊為1的bit清零
            // 也就是為獲取下一次的最右可用列使用做準備,
            // 程式將來會回溯到這個位置繼續試探
            pos -= p;

            // row + p,將當前列置1,表示記錄這次皇后放置的列。
            // (ld + p) << 1,標記當前皇后左邊相鄰的列不允許下一個皇后放置。
            // (ld + p) >> 1,標記當前皇后右邊相鄰的列不允許下一個皇后放置。
            // 此處的移位操作實際上是記錄對角線上的限制,只是因為問題都化歸一行網格上來解決,所以表示為列的限制就可以了。
            //顯然,隨著移位,在每次選擇列之前進行,原來N×N網格中某個已放置的皇后針對其對角線,上產生的限制都被記錄下來了
            test(col + p, (ld + p) << 1, (rd + p) >> 1);
        }
    }else{
        // row的所有位都為1,即找到了一個成功的佈局,回溯
        sum++;
    }
}

思想:也是一行一行進行遞迴,看是否可以進行放置皇后,然後進行下一行,不行再回溯回來重新進行下一個位置的選取,其中需要三個引數:col,ld,rd,這個引數只考慮當前行對下一行的影響。


#include<bits/stdc++.h>

using namespace std;

// sum用來記錄皇后放置成功的不同佈局數;upperlim用來標記所有列都已經放置好了皇后。
long sum = 0, upperlim = 1;
// 試探演算法從最右邊的列開始。
void test(long col, long ld, long rd)
{
    if (col != upperlim){
        // row,ld,rd進行“或”運算,求得所有可以放置皇后的列,對應位為0,
        // 然後再取反後“與”上全1的數,來求得當前所有可以放置皇后的位置,對應列改為1
        // 也就是求取當前哪些列可以放置皇后
        long pos = upperlim & ~(col | ld | rd);
        while (pos){
            // 拷貝pos最右邊為1的bit,其餘bit置0
            // 也就是取得可以放皇后的最右邊的列
            long p = pos & -pos;//類似樹狀陣列中操作,取一個數二進位制的最後一個1

            // 將pos最右邊為1的bit清零
            // 也就是為獲取下一次的最右可用列使用做準備,
            // 程式將來會回溯到這個位置繼續試探
            pos -= p;

            // row + p,將當前列置1,表示記錄這次皇后放置的列。
            // (ld + p) << 1,標記當前皇后左邊相鄰的列不允許下一個皇后放置。
            // (ld + p) >> 1,標記當前皇后右邊相鄰的列不允許下一個皇后放置。
            // 此處的移位操作實際上是記錄對角線上的限制,只是因為問題都化歸一行網格上來解決,所以表示為列的限制就可以了。
            //顯然,隨著移位,在每次選擇列之前進行,原來N×N網格中某個已放置的皇后針對其對角線,上產生的限制都被記錄下來了
            test(col + p, (ld + p) << 1, (rd + p) >> 1);
        }
    }else{
        // row的所有位都為1,即找到了一個成功的佈局,回溯
        sum++;
    }
}

int main()
{
    int n;
    // 因為整型數的限制,最大隻能32位,
    // 如果想處理N大於32的皇后問題,需要用bitset資料結構進行儲存
    scanf("%d",&n);
    if ((n < 1) || (n > 32)){
        printf(" 只能計算1-32之間\n");
        exit(-1);
    }
    printf("%d 皇后\n", n);
    // N個皇后只需N位儲存,N列中某列有皇后則對應bit置1。
    upperlim = (upperlim << n) - 1;
    test(0, 0, 0);
    printf("共有%ld種排列\n", sum);
    return 0;
}

相關推薦

目前解決N皇后問題辦法操作

也是使用遞迴+回溯的辦法:只不過使用了位運算代替陣列,使得效率更高 其核心程式碼: // 試探演算法從最右邊的列開始。 void test(long col, long ld, long rd) { if (col != upperlim){ //

N皇后

問題: n皇后問題:輸入整數n, 要求n個國際象棋的皇后,擺在 n*n的棋盤上,互相不能攻擊,輸出全部方案。 #include <iostream> using namespace std; int N; int queuePos[100];//用來描述每一個皇后所擺的列數 vo

N皇后 演算法

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

:全排列實力蒙

#include <iostream> using namespace std; void swap(int &a,int &b) {  int temp=a;   a=b;   b=temp; } void pai_xu(int a[]

到動規學習筆記

區別:動態規劃是由已知推為止,由子問題推大問題,由邊界值逆推,相當於遞迴的逆過程。 解題思想: 1.分解子問題:將原問題分為若干子問題,子問題形式與原問題相似,規模減小,子問題的解求出來即儲存,不影響其他子問題,避免重複求解。 2.確定狀態 狀態就是與解相關的一組變數

6-2 計算Ackermenn函式 15 分

6-2 遞迴計算Ackermenn函式 (15 分) 本題要求實現Ackermenn函式的計算,其函式定義如下: 函式介面定義: int Ack( int m, int n );    其中m和n是

程式設計方法練習--輸出單鏈表 10 分

本題要求用遞迴方法編寫遞迴函式實現無頭結點單鏈表的輸出操作函式。L是一個不帶頭結點的單鏈表,函式void ListPrint_L_Rec(LinkList L)要求用遞迴的方法輸出無頭結點之單鏈表中各個元素的值,每個元素的前面都有一個空格(包括首元素)。遞迴思想可借鑑下述程式碼中連結串列建立的遞

Java解決n皇后問題

題目 八皇后問題是一個以國際象棋為背景的問題:如何能夠在 8×8 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直接吃掉其他的皇后?這道題目也可以稍微延伸一下,變為 N×N的棋盤上放置N個皇后,其他條件相同。 下面介紹一種比較簡單易懂的實現方式。 程式碼 impo

回溯法解決N皇后問題

八皇后問題 在棋盤上放置8個皇后,使得它們互不攻擊,此時每個皇后的攻擊範圍為同行同列和同對角線,要求找出所有解。 遞迴函式將不再遞迴呼叫它自身,而是返回上一層呼叫,這種現象稱為回溯(backtracking)。 當把問題分成若干步驟並遞迴求解時,如果當前步驟沒有合法選擇,則函式將返回

回溯法解決N皇后問題以四皇后為例

回溯法解決N皇后問題(以四皇后為例) 其他的N皇后問題以此類推。所謂4皇后問題就是求解如何在4×4的棋盤上無衝突的擺放4個皇后棋子。在國際象棋中,皇后的移動方式為橫豎交叉的,因此在任意一個皇后所在位置的水平、豎直、以及45度斜線上都不能出現皇后的棋子,例子 要求程式設計求出符合要求的情

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

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

資料結構——八皇后解法

程式碼來源:https://www.cnblogs.com/houkai/p/3480940.html 參考程式碼:(註解多為自己填寫) #include <iostream> #include <stdlib.h> using namespace std;

[leetcode] 51. N-Queens (

遞迴,經典的八皇后問題。 利用一位陣列儲存棋盤狀態,索引表示行,值為-1表示空,否則表示列數。 對行進行搜尋,對每一行的不同列數進行判斷,如果可以擺放符合規則,則擺放,同時遍歷下一行。 遍歷過程中,若已經遍歷了n行,則儲存該狀態。 Runtime: 4 ms, faster than 91.

Python求出列表包括列表中的子列表大值

          Python遞迴求出列表(包括列表中的子列表)中的最大值 要求:求出列表中的所有值的最大數,包括列表中帶有子列表的。 按照Python給出的內建函式(max)只能求出列表中的最大值,無法求出包括列表中的子列表的最大值 Python3程式碼如下: #

一維陣列解決n皇后問題(暴力法)

     以5皇后為例遞迴實現:考慮每行只放置一個皇后、每列也只能放置一個皇后,那麼如果把n列皇后所在的行號依次寫出,那麼就會是1-n的一個排列。上圖a中的排列為24135,對於b來說就是35142。於是就只需要列舉1-n的所有排列,檢視每個排列對應的放置方案是否合法,統

整數劃分問題(python)-- and 動態規劃m個盤裡放n個蘋果思想類似

這篇部落格旨在對正整數劃分的多種題目就遞迴和動態規劃進行討論與總結 以下將正整數劃分分為三種題型:1.一般性,即對個數以及大小以及重複性不加約束 2.對重複性有約束 3.對元素的個數有約束。至於每個元

皇后 只能得到路線個數 但是沒有輸出圖

#include <iostream> #include <stdio.h> using namespace std; static int gEightQueen[8] = {0}; static int gCount = 0; void print() { int

C++ 八皇后 演算法實現

八皇后問題感覺是遞迴演算法中比較簡單的一種,核心思想就是放置之前檢查行列四個斜方位即可,共92種方案,還是挺有趣的,和漢諾塔一樣,應該屬於遞迴比較經典的問題 #include<iostream> using namespace std; int g_count=

回溯法解決N皇后問題java實現

1.簡單介紹回溯法思路,就是將所有的結果變成一棵樹,從樹的結點開始訪問,採用深度優先策略,從樹的根結點開始訪問,如果滿足條件,繼續訪問下一層,如果不滿足條件,返回上一個結點,繼續訪問其它結點。重複操作。 2. 對於N皇后問題,我特意做了一張圖片。首先放置第一

求陣列小值分治思想

求陣列最大最小值我們可以用遍歷或者最簡單的排序方法來實現,但是那樣子的時間複雜度將會大很多,因此我們可以採用分治思想來求最大最小值,即先求左右兩部分,即先求出左半部分的最大最小值,再求出右半部分的最大最小值,然後再把左右兩部分的最大最小值合起來求總的最大最小值。 程式碼如下