回溯法——八皇后问题【通俗易懂】

回溯法——八皇后问题【通俗易懂】

因为最近在学习算法,所以今天在这里对回溯法中的八皇后问题,进行一下归纳和总结,真的是用不能再通俗的语言去解释了,看不懂请自绝与人民。

一、基本定义

回溯法(back track method)是在包含问题的所有可能解的解空间树中,从根结点出发,按照深度优先的策略进行搜索,对于解空间树的某个结点,若满足约束条件,则进入该子树继续搜索,否则将以该结点为根结点的子树进行剪枝。

二、适用范围
可避免搜索所有的可能解,适用于求解组合数较大的问题。

三、八皇后问题
问题:在8 x 8的棋盘上摆放8个皇后,而且八个皇后中的任意两个是不能处于同一行、同一列、或同一斜线上。

【分析】
在8 x 8的棋盘上面放置8个皇后,而且还要不在不同一行和不在同一列,不在同一斜线上,所以每行肯定是得放一个,但是位置就有好多的可能,只要满足上面的要求即可。
设棋盘是一个8 x 8矩阵,皇后i和皇后j的摆放位置分别为(i,Xi)和(j,Xj),要想这些皇后不在同一条斜线上,则需要这两个坐标点的斜率不等于 1 或 – 1。
也就是满足|Xj —Xi | ≠ |j – i|
这里采用迭代法解决八皇后问题,迭代就是循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

迭代的代表性例子:实数累加

int v=1;
for(i=2;i<=100;i++)
{
v=v+i; //1 ——100的累加
}
【具体步骤】

1、这里的八个皇后用k = 0,1,2,3,4,5,6,7来表示。
2、第一个皇后放在8 x 8矩阵的(0 , 0)位置,也就是k = 0 ,x[k] = 0 ,这里的k表示行和皇后k,x[k]表示列。
3、放完第一个皇后之后,就要放置第二个皇后,因为不能在同一行,所以第二个皇后肯定在第二行放,这个时候到底在哪一列还没有确定。
4、在确定第二个皇后到底在哪一列的时候,就要用到一个判断函数,这个函数主要是确定皇后不在同一列和同一斜线上。

checkint k),检查皇后k是否会发生冲突。
int check(int k){  //查看k皇后是否满足约束条件 
    for(int i=0;i<k;i++)
        if (x[i]==x[k] || abs(x[i]-x[k]) ==abs(i-k))  //满足不在同一条斜线和同一列 
           return 1;
        return 0;
}

5、若发生了冲突【即皇后在同一列或同一斜线上】,就x[k]++,一直找到不发生冲突的位置或越界。
6、在找到皇后的位置之后,要先判断一下是否皇后都找到了合适的位置。
7、若还有剩余的皇后或发生越界,则分情况处理,若是还有剩余的皇后,则k = k+1,摆放下一个皇后,若是发生越界,则说明需要回溯,则x[k] = -1 ,k = k – 1

八皇后问题C++代码:

#include<iostream>
using namespace std;
#include<stdlib.h>
static int *x;  //用x数组来存放解向量
static int sum; //用sum变量来记录有几个解
int check(int k){  //查看k皇后是否满足约束条件 
    for(int i=0;i<k;i++)
        if (x[i]==x[k] || abs(x[i]-x[k]) ==abs(i-k))  //满足不在同一条斜线和同一列 
           return 1;

        return 0;

} 
void queen(int n){

     int k = 0;            //从 皇后0 开始放
     sum = 0;

    while(k>=0){
        x[k]++;           //摆放第k个皇后(第一次摆放皇后0) 
        while(x[k]<n && check(k) == 1)     //对皇后k进行检测,直到不发生冲突或x[k]越界 

          x[k]++;    //检测下一列 

        if(x[k]<n && k == n-1)
        {

          for(int i =0;i<n;i++)
           cout<<x[i]+1<<" ";
           cout<<endl;
           sum++; 

        }
        if(x[k]<n && k<n-1)     //若皇后还没有摆放完,就摆放下一个皇后k = k+1 

           k++;

        else                    //否则就是发生了越界,要进行回溯 
        { 

           x[k]=-1;         
           k--;  

        }

    }  
    if(sum == 0) 
        cout<<"无解"<<endl;
} 
int main(){

    int n =8; 
    x = new int[n+1];
    for(int i=0;i<n;i++){
        x[i] = -1;
    }

    queen(n);
    cout<<"一共解的个数为 :"<<sum<<endl;
    return 0;
}
    原文作者:回溯法
    原文地址: https://blog.csdn.net/pigpig_fly/article/details/53510852
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞