1. 程式人生 > >回溯法與N皇后問題

回溯法與N皇后問題

N皇后問題要求求解在N*N的棋盤上放置N個皇后,並使各皇后彼此不受攻擊的可能的棋盤佈局,皇后彼此不受攻擊的所有可能的佈局,皇后彼此不受攻擊的約束條件是:任何兩個皇后均不能在棋盤同一行、同一列或者在對角線上出現。

由於N皇后問題不允許兩個皇后在同一行,所以,可用一維陣列X表示N皇后問題的解,X[i]表示第i行的皇后所在的列,條件表述如下:

  • X[i] = X[s],則第i行和第s行皇后在同一列上
  • 如果第i行的皇后在第j列,第s行的皇后在第t列,即X[i] = j 和 X[s] = t,則只要i - j = s- t 或者 i + j = s + t,說明兩個皇后在對角線上,對兩個等式進行變換後,得到結論,只要|i- s| = |j - t|(即|i- s| = |x[i] - x[s]|),則皇后在同一對角線上

解N皇后問題需要遍歷解空間樹,遍歷中要隨時判定當前棋盤佈局是否滿足要求,符合要求則繼續向下遍歷,直至判斷得到一個滿足約束條件的葉子結點,從而獲得一個滿足要求的棋盤佈局,不符合要求的結點將被捨棄(稱之為剪枝),並回溯到上一層的結點繼續遍歷,當整棵樹遍歷結束時,已獲得所有滿足要求的棋盤佈局
這裡寫圖片描述

上面的就是高度為3的解空間樹,樹的每一層與棋盤的每一行是對應的,首先選擇第一行的皇后的位置的時候,是有三個選擇的,而這三個選擇都是不發生衝突的,因為此時棋盤上還沒有任何皇后,當選擇第二行的皇后的位置時,對於以上一次選擇的為根的子樹而言,只有兩種選擇,而此時就需要判斷是否與之前的選擇有衝突,如果有衝突的話就需要剪枝(就是說這種方法不符合要求,不必再繼續往下嘗試了),按照這種方法直至找到滿足題意的結果進行輸出。

皇后位置滿足約束條件的判定如下:

int place(int s) {
    int i = 1;
    for(; i < s; i++) {
        if(abs(i-s) == abs(X[i]-X[s]) || X[i] == X[s]) {
            return false;
        }
    }

    return true;
} 

回溯演算法:

void Trial(int i, int n) {
    int j, k;
    if(i > n) {
        //輸出 
        for(k = 1
; k <= n; k++) { printf("%d ", X[k]); } printf("\n"); } else { for(j = 1; j <= n; j++) { X[i] = j; if(place(i)) { Trial(i+1, n); } } } }

完整程式碼:

#include<stdio.h>
#include<math.h>
#include<malloc.h>

#define true 1
#define false 0

void Trial(int i, int n, int *X);
int place(int s, int *X);

int place(int s, int *X) {
    int i = 1;
    for(; i < s; i++) {
        if(abs(i-s) == abs(X[i]-X[s]) || X[i] == X[s]) {
            return false;
        }
    }

    return true;
} 
void Trial(int i, int n, int *X) {
    int j, k;
    if(i > n) {   //輸出 
        for(k = 1; k <= n; k++) {
            printf("%d ", X[k]);
        }
        printf(" \n");
    } else {
        for(j = 1; j <= n; j++) {
            X[i] = j;
            if(place(i, X)) {
                Trial(i+1, n, X);
            }
        }
    } 
}


void main(void) {
    int n;
    int *Queen = NULL;
    printf("請輸入皇后的個數.\n");
    scanf("%d", &n);
    Queen = (int *)malloc(sizeof(int) * (n+1));
    Trial(1, n, Queen); 
} 

執行結果:
這裡寫圖片描述

相關推薦

回溯N皇后問題

N皇后問題要求求解在N*N的棋盤上放置N個皇后,並使各皇后彼此不受攻擊的可能的棋盤佈局,皇后彼此不受攻擊的所有可能的佈局,皇后彼此不受攻擊的約束條件是:任何兩個皇后均不能在棋盤同一行、同一列或者在對角線上出現。 由於N皇后問題不允許兩個皇后在同一行,所以,可用

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

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

回溯解決N皇后問題

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

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

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

【基礎演算法】回溯皇后問題

#include"iostream" #include"stdlib.h" using namespace std; int x[8],tot=0; bool B(int x[],int k) { int i; for(i=0;i<k;i++) if(x[i]==x[

POJ 1321 簡單搜尋 回溯n皇后問題

要求:在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。 方法:回溯法 1.深搜函式的引數為行數。 2.used[i]=1表示第i列已

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

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

java回溯解決n皇后問題

先看問題吧 問題描述:八皇后問題是一個以國際象棋為背景的問題:如何能夠在 8×8 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。 關於n皇后問題相關的解法很多,在這裡大家可以看看我的寫法

使用回溯解決八皇后問題(同樣適用於N皇后)。

在學習資料結構的時候,看到了一道八皇后的問題。寫完後,再去網上檢視發現原來這個問題有這麼多的優化解法,相比之下相形見絀。但我還是記錄下來,有興趣的小夥伴可以看看。 先大致說下我的思路 建立一個初始化值為0的8x8的陣列,0代表無皇后且不在其他

【演算法分析】回溯解八皇后問題(n皇后問題)

回溯法解題思路: (1)針對所給問題,定義問題的解空間;    (2)確定易於搜尋的解空間結構;    (3)以深度優先方式搜尋解空間,並在搜尋過程中用剪枝函式避免無效搜尋。 八皇后問題:

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

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

遞歸回溯解決八皇后問題

一、八皇后問題 皇后是國際象棋中威力最大的棋子。她可以攻擊同一行、同一列以及與她處在斜線上的棋子。八皇后問題在1848年由國際西洋棋棋手馬克斯·貝瑟爾提出:如何在8x8格的棋盤上擺放八個皇后,使她們不能互相攻擊? 上圖是92種擺法中的其中一種。 一個有用的經驗是:在正式

回溯求八皇后問題

本演算法將第第x行皇后的列編號記為C[x],回溯求符合條件的tot,遞迴邊界為從0到7(八皇后),皇后為逐行放置,cur-C[cur] == j-C[j] || cur+C[cur] == j+C[j]判斷皇后是否在同一對角線上話不多說,直接上程式碼: #include<s

[回溯] 2 四皇后問題

前言 回溯法 1-求n個元素的集合的冪集中狀態變化樹是一棵滿二叉樹:樹中每個葉子結點的狀態都是求解過程中可能出現的狀態(即問題的解)。 【然而】很多問題用回溯和試探求解時,描述求解過程的狀態樹不是一棵滿的多叉樹 【非滿多叉樹】不是滿的多叉樹:當試探過程中出現的狀態和問題所求解產生

第一次上傳程式碼 處女秀-回溯解決八皇后問題

c語言 # include<stdio.h> # include<math.h> # define max 8 int queen[max],sum=0; int check(int n){ int i; for(i=0;i<n;i+

小朋友學經典演算法(14):回溯和八皇后問題

一、回溯法 回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。 二、八皇后問題 (一)問

回溯(八皇后問題)及C語言實現

       回溯法,又被稱為“試探法”。解決問題時,每進行一步,都是抱著試試看的態度,如果發現當前選擇並不是最好的,或者這麼走下去肯定達不到目標,立刻做回退操作重新選擇。這種走不通就回退再走的方法就是回溯法。 回溯VS遞迴 很多人認為回溯和遞迴是一樣的,其實不然。在回溯

回溯動態規劃例項分析

回溯法與動態規劃 1、回溯法 1.1 適用場景 回溯法很適合解決迷宮及其類似的問題,可以看成是暴力解法的升級版,它從解決問題每一步的所有可能選項裡系統地選擇出一個可行的解決方案。回溯法非常適合由多個步驟組成的問題,並且每個問題都有多個選項。當我們從一步選擇了其中

回溯之八皇后問題

關於八皇后的介紹我就不再這裡多囉嗦了,大家可以自行百度。 現在,我來說明一下八皇后的限制條件: 1.在同一行內,皇后不能出現兩次; 2.在同一列內,皇后不能出現兩次; 3.在同一條對角線內,皇后不能出現出現兩次。 問題是:找出一個位置使得八皇后同時存放在棋盤上且互相

回溯解決N後問題(java描述)

1.問題描述: N後問題就是在一個N*N的棋盤上放置N個皇后,要求這N個皇后中的任何兩個皇后不在同一行或同一列或同一斜線上。 2.演算法設計: 使用x[1...n]來表示問題的解。x[i]表示第i個皇后放在棋盤的第i行第x[i]列。因為i是唯一的,所以i是不可能相同的,所以在判斷皇后