n皇后問題(分析)

這道題須要用到回溯算法,如今在這裏先簡單的介紹一下這個算法:算法

回溯算法也叫試探法,它是一種系統地搜索問題的解的方法。回溯算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。用回溯算法解決問題的通常步驟爲:函數

一、定義一個解空間,它包含問題的解。spa

二、利用適於搜索的方法組織解空間。code

三、利用深度優先法搜索解空間。blog

四、利用限界函數避免移動到不可能產生解的子空間。遞歸

問題的解空間一般是在搜索問題的解的過程當中動態產生的,這是回溯算法的一個重要特性。io

 

首先,看一個簡單的程序;for循環

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void function(int a)
 5 {
 6     if (a > 0)
 7     {
 8         printf("%d\n", a);
 9         function(a - 1);
10     }
11 }
12 
13 int main(void)
14 {
15     int a = 3;
16     function(3);
17     system("PAUSE");
18     return 0;
19 }

輸出:3 2 1function

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void function(int a)
 5 {
 6     if (a > 0)
 7     {
 8         function(a - 1);
 9                 printf("%d\n",a);
10     }
11 }
12 
13 int main(void)
14 {
15     int a = 3;
16     function(3);
17     system("PAUSE");
18     return 0;
19 }

輸出:1 2 3class

首先第一個不難理解,第二個,首先進行三次遞歸,分別是function(2),function(1),function(0)=>a=3,a=2,a=1;當到a=1遞歸執行結束,就會接着往下執行,執行printf,因此此時輸出1,而後,返回到上一級遞歸,function(1),執行結束後,再次執行printf,輸出1...

 

八皇后問題:

八皇后問題,是一個古老而著名的問題,是回溯算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。 高斯認爲有76種方案。1854年在柏林的象棋雜誌上不一樣的做者發表了40種不一樣的解,後來有人用圖論的方法解出92種結果。計算機發明後,有多種計算機語言能夠解決此問題。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define max 8//定義最大方格 
 5 
 6 int a[max],sum=0;//定義全局變量
 7 
 8 int check_function(int n) { //檢查當定一個點時,以行爲單位掃描(a[n]爲橫座標)遍歷其餘列的位置是否能知足要求
 9     int i;
10     for(i=0; i<n; i++)/*i<n,而不是i<max,這裏用法是:首先定的一個點爲起始點,這個點確定正確,而後對下列掃描,找到,和上一列定那個點一塊兒知足條件的點,接着第三第四列同樣,到第八列(max),又找到點時,這時候知足第30行代碼的輸出條件,輸出,找到一組
11     ,接着第26~28行代碼,至關於將定點縱座標加一,進行移位操做,而後到check_function函數中進行與上面相似的操做*/
12     {
13         if(a[i]==a[n]||abs(a[i]-a[n])==abs(i-n)) { //a[i]==b[n]表示在同一排的狀況,後者爲在同一對角線上(記住abs求絕對值函數)
14             return 1;//不知足條件返回1
15         }
16     }
17     return 0;//知足條件返回0
18 
19 }
20 
21 int func(int n) { //定義一個進行對定點改變與輸出結果的函數
22     int i,t;
23     for(i = 0; i < max; i++) {
24         a[n]=i;//假設的點,當每次知足條件返回1時,會再次進行上面的for循環,對i進行加一操做,至關於對縱座標操做,下移一位
25         if(check_function(n)==0) { //結合上一個給a[n]賦值,經過判斷是否符合條件,讓a[n]的值爲每一列知足條件的值(縱座標),n爲橫座標
26             if(n==max-1) { //max-1 說的是最後一列,當橫座標數等於最後一列,且知足了檢驗,就說明這是一組中的最後一個,因而輸出知足條件的a[n]
27                 for(t=0; t<n; t++)
28                     printf("(%d,%d),",t,a[t]);//這樣打印的緣由:到這裏,每一個a[n]實際是知足條件的位置
29                 printf("\n");
30                 sum++;
31             } else {
32                 func(n+1);//若知足了檢驗,卻不知足是最後一項,則說明這只是一組中的一個,且不是最後一個,由於推出結果是按列進行掃描,因此,橫座標向後移一位
33             }
34         }
35     }
36 }
37 
38 
39 int main(void) {
40     func(0);//定橫座標爲零
41     printf("sum=%d\n",sum);//打印出擺放方式數
42     return 0;
43 }

相關文章
相關標籤/搜索