N皇后问题

来源:互联网 发布:懒人听书软件 编辑:程序博客网 时间:2024/06/08 11:40

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