题目-八 / n皇后C++解-深搜

八皇后与n皇后问题的C++解

前言


回溯法也称试探法,用于寻找一个问题的可行解。该方法首先暂时泛起问题规模大小的闲置,从最小规模开始将问题的候选解按某种顺序逐一枚举和检验,选择一个可行的候选解,然后扩大规模,继续试探。打到要求的规模时,所有的候选解就形成了问题的可行解。8皇后和n皇后的问题就是基于回溯法解决的。

< 八皇后问题 >


题目要求:在一个8*8的棋盘上放置 8 个皇后,使8个皇后中没有两个或两个以上的皇后会出现在同一行、同一列、或同一对角线上。

一、解决思路:


1.先简单表示出我们想要的伪代码。

queen_all (k)   //k是这次放置皇后的所在列,如果k=1,那就是第一列。
{
    for (i=1;i<=8;++i)  //i是行,先从第一行开始试探
    if  (如果把皇后放在 k 列 i 行 是可行的){
        在该列第 i 行放入皇后
        if (k==8) 输出解
        else queen_all(k+1)     //继续排列下一行
    }
}

2.针对这个伪代码,我们要解决如下问题:

  • 如何判断是否在 k 列 i 行可行?
  • 放下一个皇后后,怎么让其所在行,列,两条斜线都不能再次放置另一个皇后?
  • 如果某一列的每一行都无法再次放置皇后,要怎么回溯到上一次?
  • 如果k==8时,输出一个可行解后怎么在查找下一个可行解?
  • -最后我们要怎么退出?

A. 对于①、②问题,我们先要找到一种方式来储存可行解,当然我们也可以用二维数组来模拟棋盘,每放置一个皇后就把这位置标记下来,并把所在行列斜线都标记为false,再进行下一次放置皇后时,根据该行该列是否是 false 来放置。但自习思考这样会造成标记和输出上的麻烦。为了使问题便于思考和简化代码,我们可以采取以下方法。

  • 用一维数组 col[9] 来表示每列上皇放置的位置,如row[A]=B:代表第 A 列第9行放置了一个皇后。
  • 用 bool row[9],digLeft[16],digRight [16]分别表示每行,左低右高线和右低左高线上是否被禁止放置皇后。如row[A]=false,digLeft[B]=false,digRight[C]=false,表示第 A 行,第B条左低斜线和第C条右高斜线上不能放置皇后。至于列就不用了管它了。通过规律我们可以把 B 和 C 用 k 和 i 表示出来。

B. 对于③,但循环 i=9 时自然会退出回溯到上一次放置皇后,不过我们要额外加一条代码来取消上一次的标记。对于④也是同理。

C. 当我们把所有能够试探的方法试探玩后,k=9,自然就会退出递归。


一切都思考清楚后就可以释放代码了,好耶!

二、代码实现


void queen_all(int k)   //开始传递数字'1',数组开全局
{
    int i=0;

    for (i=1;i<=8;++i)
    {
        if (row[i]!=1&&digLeft[k+i-1]!=1&&digRight[8+k-i]!=1)   //之前偷懒把数组全初始化为 0 ,所以用1来代替false。
        {
            col[k]=i;
            row[i]=digLeft[k+i-1]=digRight[8+k-i]=1;    //标记
            if (k==8)
            {
                for (int j=1;j<=8;++j)
                    cout<<col[j]<<' ';//输出解,如“8 4 1 3 6 2 7 5”代表第一列第八行,第二列第四行......第八列第五行
                cout<<endl;
            }
            else queen_all(k+1);    //跳转到下一行
            row[i]=digLeft[k+i-1]=digRight[8+k-i]=0;    //清除标记
        }
    }
}

总之还是挺容易的。除了我这个憨憨之前想用二维数组强解

< n皇后问题 >


简单,吧8换成n的事,函数多传递个n就好==

顺带一提如果按照行输出(以上是按照列输出的),则结果会一样= =。
上完整版代码

#include<iostream>
using namespace std;

void queen_all(int k,int n);

int col[100]={0},times=0;     //用times来记录一共多少种结果
bool row[100]={0},digLeft[100]={0},digRight[100]={0};

int main()
{
    int n=0;

    cin>>n;

    queen_all(1,n);

    cout<<times;

    return 0;
}

void queen_all(int k,int n)
{
    int i=0;
    for (i=1;i<=n;++i)
    {
        if (row[i]!=1&&digLeft[k+i-1]!=1&&digRight[n+k-i]!=1)
        {
            col[k]=i;
            row[i]=digLeft[k+i-1]=digRight[n+k-i]=1;
            if (k==n)
            {
                for (int j=1;j<=n;++j)
                    cout<<col[j]<<' ';
                cout<<endl;
                ++times;
            }
            else queen_all(k+1,n);
            row[i]=digLeft[k+i-1]=digRight[n+k-i]=0;
        }
    }
}


最后 --- *** 八皇后能帮助我们能够理解回溯法的思想,是一次不错的训练。 感觉皇后问题比快排和搜索简单。
学习自:**C++程序设计**|思想与方法(我的教材)
posted @ 2020-11-07 19:32  七铭的魔法师  阅读(512)  评论(0编辑  收藏  举报