n皇后問題(分析)


這道題需要用到回溯算法,現在在這里先簡單的介紹一下這個算法:

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

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

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

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

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

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

 

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

 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 1

 

 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 3

首先第一個不難理解,第二個,首先進行三次遞歸,分別是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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM