八皇后问题递归解法

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当 n = 1 或 n ≥ 4 时问题有解。

求解:

#include <iostream>
using namespace std;

const int Q_number = 8  ;//皇后数量
int queens[Q_number][Q_number] = {0};//初始化数组
static int q_count = 0;//记录解数量

//用于输出结果  1表示皇后
void printBroad(){
    for(int i =0;i < Q_number;i++){
        for(int j = 0;j < Q_number;j++){
            cout<<queens[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<endl;
}

//测试queue[row][column]是否符合条件
bool setQueen(int row,int column){

    //从第一行开始摆放皇后 所以第一行不会出现不能摆放情况
    if(row == 0){
        queens[row][column] = 1;    
        return true;
    }

    //判断同一列是否存在皇后
    for(int i = 0;i < row ;i++){
        if(queens[i][column] == 1)
            return false;
    }

    //用于是从第一行开始摆放  所以只需检验左上角和右上角两个方向即可
    //检验左上角是否存在皇后
    for(int i = row - 1,j = column - 1;i >= 0 && j >= 0;i--,j--){
        if(queens[i][j] == 1){
            return false;
        }
    }

    //检验右上角
    for(int i = row - 1,j = column + 1;j < Q_number  && i >= 0;j++,i--){
        if(queens[i][j] == 1)
            return false;
    }

    //符合摆放皇后条件 将对应位置置1
    queens[row][column] = 1;
    return true;
}

//递归函数 求解第row行摆放皇后条件
void solve(int row){

    //遍历完成  输出结果
    if(row == Q_number){
        q_count++;
        printBroad();
        return ;
    }

    //遍历第row行  寻找符合条件的皇后位置
    for(int i = 0;i < Q_number;i++){
        //试探row行 i列是否符合条件
        if(setQueen(row,i)){
            //符合条件  求解下一行
            solve(row +1);
        }
        //row行 i列情况试探完毕  将对应位置重置为0  防止干扰下次结果
        queens[row][i] = 0;
    }
}

int main(){
    solve(0);//开始求解
    cout<<"count:"<<q_count<<endl;
    system("pause");
    return 0;
}

代码注释应该是比较详细的,求解的关键是理解递归函数。通过递归函数遍历每一行,寻找符合条件的解。

其实八皇后问题很早就听说过,但是由于算法方面实在很菜,一直不会求解。最近开始学习算法,在leetcode上又看到这个经典的皇后问题,于是下决心要求出结果。由于这个问题实在经典,google一下之后出来一堆求解方法,都是大同小异,基本都是回朔法(backtracking)求解,具体有递归和非递归两种解法。由于最近在leetcode上刷了一些二叉树的题,基本都是递归求解,所以索性也用递归求解,经过一下午的努力,终于求出了结果,激动地不行啊。lol

最后再说下递归。在刚开始学习递归的时候其实我是拒绝的,因为递归又不好理解,效率又低(好吧,主要是理解不了)。所以在平时写程序的时候基本不用递归。后来学习数据结构的时候接触到二叉树,要写算法遍历树(前中后序遍历),书上的解法就是递归解法,那时候开始感受到递归解法的简洁和强大,简简单单的的几行代码就可以完成这么多的计算。最近又开始重学算法,在leetcode刷题碰到很多二叉树的问题,刚开始很头疼,写一大段代码,最后结果还是错的,无奈只能去看discuss里各位AC的大神的解法,里面有很多优秀的代码,有的甚至只要一行就能解决(虽然只是easy的问题),当时我就被震惊了,这TM还能这么简单,于是,每次碰到的问题我都先考虑能不能用递归求解,刷了一些题目之后稍微有了一些感觉,递归其实就是将一个大问题分解成相似的小问题,通过解决一个个小问题,最后解出大问题,比如八皇后问题,一下子求解所有皇后摆放位置很困难,所以我们通过递归先解决第一个皇后位置,然后第二个,第三个知道第N个。而且,递归也是一些别的算法,比如,分治,动态规划的基础。入门递归之后接下来就可以开始学习分治,动态规划之类的算法了,未来的路还很漫长。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值