Loading

[蓝桥杯][基础练习VIP]2n皇后问题

问题描述
  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2

这是一道典型的dfs,基本思路是穷尽尝试,如果某次尝试失败,则退回上一步重新选择。
接下来对这一题作具体分析:
1.要找出所有可能,每种可能要求同行,同列,同对角线上不能出现同种颜色皇后,首先想到的应该是先放一种颜色的皇后,再放另一种。
那么先放黑皇后,再放白皇后,每种皇后都从第一行遍历到最后一行,每行再逐列尝试。
2.在每次放皇后时,需要判断同行,同列,同对角线上是否已经出现了同种颜色的皇后,所以每次放过皇后后要标记这三个值。接下来讲如何标记这三个值:
3.因为是从第一行遍历到最后一行,所以不需要考虑行,而列只需要设置一个数组,每次放入一个皇后,在相应的vis数组标记为1。
至于同对角线,有两种情况,从左下到右上的对角线,我暂且称之为斜1;从左上到右下,记作斜2;
(1)很容易可以看出在斜1同一条对角线上的横纵坐标相加是一个固定的数,且每条对角线不会重复,0,2,4,6.....所以直接把这个相加之后固定的数作为数组的下标,每次放入之后标记为1;

(2)同理,斜2同一条对角线上横纵坐标相减为一个固定的数,为了防止出现负数,统一加7
(具体见18,19行和42,43行)
到这里这道题的难点就结束了,代码中有更详细的注释

#include <iostream>
using namespace std;
int n, ans = 0;
int qp[8][8]; // 棋盘
// 0不能放;1能放;2黑皇后;3白皇后
int lieblack[8]{0}, liewhite[8]{0}; //  0/1标记该列是否被黑/白皇后占用
int xie1black[20]{0}, xie2black[20]{0}, xie1white[20]{0}, xie2white[20]{0};
// 标记左斜行和右斜行
void dfswhite(int hang) // 参数为当前的行数
{
    if (hang == n) // 当白皇后最后一行也已经放完之后
    {
        ans++; // 已经是一种成功放置的方法
        return;
    }
    for (int lie = 0; lie < n; lie++) // 在每行中遍历
    {
        if (qp[hang][lie] == 1 && liewhite[lie] == 0 && xie1white[hang + lie] == 0 && xie2white[hang - lie + 7] == 0) // 判断条件依次为,棋盘是否能放;该列是否被同颜色皇后占用;
        // 斜1对角线是否被占用;斜2对角线是否被占用;
        {
            qp[hang][lie] = 2; // 放置皇后,依次标记
            liewhite[lie] = 1;
            xie1white[hang + lie] = 1;
            xie2white[hang - lie + 7] = 1;
            dfswhite(hang + 1); // 该行已放置,进入下一行
            qp[hang][lie] = 1;  // 回溯,移除标记
            liewhite[lie] = 0;
            xie1white[hang + lie] = 0;
            xie2white[hang - lie + 7] = 0;
        }
    }
}
void dfsblack(int hang)
{
    if (hang == n) // 当黑皇后最后一行也已经放置
    {
        dfswhite(0); // 开始放置白皇后
        return;
    }
    for (int lie = 0; lie < n; lie++) // 与dfswhite同理
    {
        if (qp[hang][lie] == 1 && lieblack[lie] == 0 && xie1black[hang + lie] == 0 && xie2black[hang - lie + 7] == 0)
        {
            qp[hang][lie] = 3;
            lieblack[lie] = 1;
            xie1black[hang + lie] = 1;
            xie2black[hang - lie + 7] = 1;
            dfsblack(hang + 1);
            qp[hang][lie] = 1;
            lieblack[lie] = 0;
            xie1black[hang + lie] = 0;
            xie2black[hang - lie + 7] = 0;
        }
    }
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cin >> qp[i][j];
        }
    }
    dfsblack(0); // 从第一行开始防止黑皇后,全部放置完后再放置白皇后
    cout << ans;
}
posted @ 2021-03-20 18:21  longwind7  阅读(125)  评论(0)    收藏  举报