回溯算法解决八皇后问题的C/C++实现

最近在学一些算法相关的知识,学习之余准备动手写一点随笔记录学习过程。在加深理解的同时分享给大家,不足之处请各位多多指正。一个人能走得很快,但一群人能走得更远。

不多说,直接上代码。

核心代码部分

void FindQueen(int row){
    if(row > 7){
        ans++;
        return;
    }

    for(int column = 0; column < 8; column ++)
        if(check(row,column)){
            arr[row] = column;
            FindQueen(row+1);
            arr[row] = -1;
        }
}

代码理解(重点

首先,我放弃了使用二维数组来表示棋盘,而是选择了一个一维数组 arr[8] 。从而棋子的摆放可以用 arr[row] = column 来表示为:在第 row 行的第 column 列处摆放了棋子(行列皆从0开始计数)。全局数组 arr[8] 在初始化时,置所有值为-1。

当 row > 7 时,已经找到一解, ans计数并返回。当 row <= 7 时,也就是还没有找到正确解的情况下,我们用 for 循环搜索第row行的所有列。这时,就存在两种情况。

  • 该行存在一个位置,且该位置上的棋子不会与之前摆放的棋子冲突
    这时,我们认为该行上的位置已经找到,修改 arr 数组,递归进入下一行。
  • 改行不存在上述位置,即该行上所有位置都会与之前摆放的棋子产生冲突
    这时,函数会回退到上一次调用它的地方并继续执行剩下的语句,即执行 arr[row] = -1。该语句恢复环境,并指出我们刚刚在 (row,column) 处放的棋子已经不可能使后续要摆放的棋子满足条件。然后 for 循环执行 column++ ,在第 row 行继续找下一个可能的位置。

check函数

bool check(int row, int column){
    for(int i = 0; i < row; i++)
        if(arr[i] == column) return false;
    
    for(int i = 0; i < row; i++)
        if(abs(row-i) == abs(column - arr[i])) return false;

    return true;
}

因为代码是逐行进行递归的,因此不会产生行冲突(一维数组也保证了这一点)。第一个for循环检查(row,column)处是否与之前摆放的棋子产生列冲突,第二个for循环则检查两条对角线冲突。

完整代码

#include <iostream>
#include <cmath>
using namespace std;

int ans = 0;
int arr[8] = {-1};

bool check(int row, int column){
    for(int i = 0; i < row; i++)
        if(arr[i] == column) return false;
    
    for(int i = 0; i < row; i++)
        if(abs(row-i) == abs(column - arr[i])) return false;

    return true;
}

void FindQueen(int row){
    if(row > 7){
        ans++;
        return;
    }

    for(int column = 0; column < 8; column ++){
        if(check(row,column)){
            arr[row] = column;
            FindQueen(row+1);
            arr[row] = -1;
        }
    }
}

int main(void){
    FindQueen(0);
    cout << ans << endl;
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容