经典算法-八皇后

1 八皇后

八皇后的问题是:

一个8X8的棋盘上,摆上8个皇后,皇后的攻击方式是,斜着,横着,竖着。要求摆的8个皇后不能够相互攻击到。

2 分析

八皇后的解法是回溯算法。

而关键问题就在于:判断某个点是否可以摆。

3 解法

3.1 使用二维数组备忘

使用二维数组做备忘,直观很多。按部就班的判断是否可以防止就行了。

#include <vector>
#include <iostream>

using namespace std;

bool aux_judge(int row, int col, vector<vector<int>> &memo)
{
    // 只用到row 的原因在于,后面的都没摆,因此可以不用判断
    // 判断同一列
    for (int i = 0; i < row; ++i)
    {
        if (memo[i][col] == 1)
        {
            return false;
        }
    }

    // 判断右斜,因此是row和col都要减少相同的
    for (int i = 1; col - i >= 0 && row - i >= 0 ; ++i)
    {
        if (memo[row - i][col - i] == 1)
        {
            return false;
        }
    }
    // 判断左斜,因此row是在减,col是在加
    for(int i=1;col+i<8&&row-i>=0;++i)
    {
        if(memo[row-i][col+i]==1)
        {
            return false;
        }
    }
    return true;
}

// row 开始摆第row-1行,ret为解的个数
void aux(int row, vector<vector<int>> &memo, int &ret)
{
    // 当row==8 的时候,也就是说前面0~7行,这8行都摆了,那么已经完成了一个解
    if (row == 8)
    {
        ret++;
        return;
    }

    // 这一行的 8 个位置依次试一下
    for (int i = 0; i < 8; ++i)
    {
        // 判断 row,i 这个点是否可以摆
        if (aux_judge(row, i, memo))
        {
            memo[row][i] = 1;
            aux(row + 1, memo, ret);
            memo[row][i] = 0; // 回溯
        }
    }
}

int eight()
{
    // 使用一个二维数组,记录已经摆的点。可以用bool的。
    vector<vector<int>> memo(8, vector<int>(8, 0));
    int ret = 0;
    aux(0, memo, ret);
    return ret;
}

  

 

3.2 使用一位数组备忘

使用一个8长度的一维数组备忘,数组的低i位,表示第i行,皇后放在arr[i]位置上。

其中判断是否可以方式的时候,是初中数学时候的知识,也就是 x+y=c1,和y-x=c2.

bool aux_check(int row, int col, vector<int> &memo)
{
    for (int i = 0; i < row; ++i)
    {
        // 判断是否有皇后在
        if (memo[i] == col)
        {
            return false;
        }

        // memo[i] + i == row + col 的含义是:
        // 当2个点的横纵坐标相加和相等的时候,就类似于 x+y =n ,那么两点在同一纸箱上
        // 同理 memo[i] -i== col -row 表示
        // 当两个点的横纵坐标差相等时,类似于 x-y =c ,那么两点也在同一直线上。
        if (memo[i] + i == row + col || memo[i] -i== col -row)
        {
            return false;
        }
    }
    return true;
}

void aux(int row, vector<int> &memo, int &ret)
{
    if (row == 8)
    {
        ret++;
        return;
    }

    for (int i = 0; i < 8; ++i)
    {
        if (aux_check(row, i, memo))
        {
            memo[row] = i;
            aux(row + 1, memo, ret);
            // memo[row] = 0;  // 这句话是可以省略的,
            // 原因在于,在 aux_check() 判断的时候并不会用到这一行。
        }
    }
}

int eight()
{
    // memo 记录的是第 i 行上的皇后位于 memo[i]列
    vector<int> memo(8);
    int ret = 0;
    aux(0, memo, ret);
    return ret;
}

  

3.2 位运算记录

位运算太渣。看不懂啊。。。。

    原文作者:perfy576
    原文地址: https://www.cnblogs.com/perfy576/p/8568437.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞