1. 程式人生 > >回溯法和棧的思想用於“八皇后問題”的求解

回溯法和棧的思想用於“八皇后問題”的求解

八皇后問題是一個經典的問題,其核心是:在n*n的棋盤上,有n個皇后,這些皇后必須位於不同行不同列上,並且不能處於同一對角線上,否則會因相互攻擊而死亡。那麼如何安排皇后們的位置呢?

我們可以利用回溯法,先確定第一個皇后的位置,之後進入下一行,確定第二個皇后的位置,再之後進入下一行,如果發現找不到一個位置安排新皇后,則回退到上一行,將上一行的皇后向後移動一列,再考慮下一行的皇后,如此迴圈,直到安排好所有的皇后為止。附上一張圖片以便於理解。
這裡寫圖片描述

具體實現的程式碼及所遇到的問題及解決如下:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int status; /*列印答案*/ status printsolution(int *x,int n){ int i=1,j=1; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ /*如果該列可以放皇后,列印“Q”*/ if(j==x[i]) printf("Q"); else printf
("*");//不能則列印星號 } printf("\n"); } printf("\n"); } status isplace(int *x,int k){ int i=1;//從第一行開始考察 /*考察前k-1行*/ for(i=1;i<=k-1;i++){ /*這是皇后相互攻擊的條件*/ if((x[i]==x[k])||(fabs(x[i]-x[k])==fabs(i-k))) return FALSE; } return OK; } status nqueen(int
*x,int n){ int k=1; x[k]=0;//先讓x[k]=0,進入迴圈後加1 while(k>0){//全部行列判斷完後,k=0 x[k]++; while(x[k]<=n&&!isplace(x,k))//尋找可以放的列 x[k]++; if(x[k]<=n){//如果找到 if(k==n)//k==n說明是完整解 printsolution(x,n); else{//k<n是不完整解 k++;//移動到下一行繼續判斷 x[k]=0;//移動到下一行之後要注意將x[k]置為0,以便從第一行開始判斷 } } else//x[k]如果大於n,則不必考慮此行,k--回溯到上一行 k--; } } int main(void){ int * x; int num=0; x=(int *)malloc(sizeof(int)*(num+1));//這裡用動態陣列儲存可以放置皇后的列 printf("請輸入皇后數目"); scanf("%d",&num); nqueen(x,num); }

2016/4/15更新:
今天覆習了八皇后問題,在此過程中發現了不少之前忽視的問題,下面加以總結以便回顧反思。
問題主要出現在status nqueen()函式中

status nqueen(int *x,int n){
    int i=1;
    x[i]=0;
    while(i>0){
        x[i]++;
        while(x[i]<=n&&!isplace(x,i))
             x[i]++;
        if(x[i]<=n){//此處進行判斷的條件是x[i]<=n,因為前一步在尋找能夠放皇后的列 
            if(i==n)//這一步的判斷條件為i==n,因為x[i]==n不能說明找到了完整解,這兩處很容易出錯,今後應謹慎對待 
                printsolution(x,n);
            else{
                i++;
                x[i]=0;//這一步在移動到下一行時一定要讓列置為0 
            }
        }
        else
            i--;
    }
}