N皇后問題
回溯法(探索與回溯法)是一種選優搜索法,又稱爲試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。
基本思想
在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。 若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。 而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束
1.問題描述
n皇后問題是遞歸和回溯法的一個典型應用。問題描述如下:對於一個n×n的棋盤,要求在其中放入互不攻擊的n個皇后。
皇后的攻擊範圍包括:
1) 同一行
2) 同一列
3) 同一對角線(包括兩個方向)
2.算法設計
問題的解可表示爲x[1:n], 表示皇后i放在棋盤的第i行的第x[i]列。
a)x[i]≠x[j] ,i≠j:不允許將任何兩個皇后放在同一列上;
b)|j-i|≠|x[j]-x[i]|: 不允許兩個皇后位於同一條斜線上。
3.算法步驟
取K爲行的編號,數組X[K]爲列的編號,先令K=1,X[K]=1,然後取K=K+1,對棋盤的下一行進行檢測,找到合法的位置,依次檢測,直到K=N 時,輸出皇后的所在的列的位置;若過程中遇到在某一行K 無合法位置,則取K=K-1,回溯到上一行,同時令X[K]=X[K]+1,再對下一行的位置進行檢測,看是否有合法皇后位置,依次得到所有的結果。
程序代碼如下:
#include <stdio.h>
#include <math.h>
typedef int bool;
#define true 1;
#define false 0;
//檢測皇后是否合法
bool place(int k, int *X)
{
int i;
i=1;
while(i<k){
if((X[i]==X[k])||(abs(X[i]-X[k])==abs(i-k)))
return false; i++;
}
return true;
}
void Nqueens(int n,int *X) {
int k;
X[1]=1;
k=1;//k表示棋盤的列,用X[k]表示當前列的行的編號
while(k>0){
int i;
X[k]=X[k]+1; //不斷的在解空間裏從小到大的試探
while((X[k]<=n)&&(!place(k, X)))
X[k]=X[k]+1; //不符合條件的馬上再取解空間的下一個值來試探。
if(X[k]<=n) //找到了一個位置,而且是合法的
if(k==n) { //是不是最後一個皇后,若是則得出一個完整解
for( i=1;i<=n;i++)
printf("%d",X[i]);
printf("\n");
}
else {//若不是最後一個皇后,則給下一個皇后找位置
k=k+1;
X[k]=0;
}
else
k=k-1; //若是找了全部的列都無法放置某個皇后,則回溯到上一個k的情況
}
}
void main() {
int n;
int X[100];
printf("請輸入皇后的個數:");
scanf("%d",&n);
printf("問題的解有:");
Nqueens(n,X); }