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); }