【ACWing】843. n-皇后问题

题目地址:

https://www.acwing.com/problem/content/845/

n n n皇后问题,在 n × n n\times n n×n的棋盘上放 n n n个皇后,使得这些皇后互相不攻击。要求输出所有方案。

输入格式:
共一行,包含整数 n n n

输出格式:
每个解决方案占 n n n行,每行输出一个长度为 n n n的字符串,用来表示完整的棋盘状态。其中”.”表示某一个位置的方格状态为空,”Q”表示某一个位置的方格上摆着皇后。每个方案输出完成后,输出一个空行。注意:行末不能有多余空格。输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围:
1 ≤ n ≤ 9 1\le n\le 9 1n9

思路是DFS。枚举每一行在哪一列放皇后。同时用三个变量分别存,哪些列已经放了皇后,还有哪些对角线已经放了皇后。对于对角线的判断,我们可以分为方向从左上到右下的对角线,和方向从右上到左下的对角线两种类型分别判断。从左上到右下的对角线,我们规定 ( 0 , n − 1 ) (0,n-1) (0,n1)所在的对角线是 0 0 0号, ( 0 , n − 2 ) (0,n-2) (0,n2)所在的对角线是 1 1 1号,等等,那么对角线的号码 k k k和上面某点的坐标 ( i , j ) (i,j) (i,j)满足 j = i + n − 1 − k j=i+n-1-k j=i+n1k,所以 k = i − j + n − 1 k=i-j+n-1 k=ij+n1;从右上到左下的对角线,我们规定 ( 0 , 0 ) (0,0) (0,0)所在的对角线是 0 0 0号, ( 0 , 1 ) (0,1) (0,1)所在的对角线是 1 1 1号,等等,那么对角线的号码 k k k和上面某点的坐标 ( i , j ) (i,j) (i,j)满足 j = − i + k j=-i+k j=i+k,所以 k = i + j k=i+j k=i+j。搜到第 n + 1 n+1 n+1行的时候说明找到了一个解,输出答案即可。代码如下:

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

void dfs(int i, int res[], int n, bool used[], bool diag[], bool udiag[]) {
    if (i == n) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
                if (res[j] == k) cout << 'Q';
                else cout << '.';
            }
            cout << endl;
        }

        cout << endl;
        return;
    }

    for (int j = 0; j < n; j++) {
        if (used[j] || diag[i - j + n - 1] || udiag[i + j]) continue;
        used[j] = diag[i - j + n - 1] = udiag[i + j] = true;
        res[i] = j;
        dfs(i + 1, res, n, used, diag, udiag);
        used[j] = diag[i - j + n - 1] = udiag[i + j] = false;
    }
}

int main() {
	int n;
    cin >> n;

    int res[n];
    bool used[n], diag[2 * n - 1], udiag[2 * n - 1];
    memset(used, false, sizeof used);
    memset(diag, false, sizeof diag);
    memset(udiag, false, sizeof udiag);

    dfs(0, res, n, used, diag, udiag);

    return 0;
}

时间复杂度 O ( n 2 n ! ) O(n^2n!) O(n2n!)(因为伴随着剪枝,实际时间达不到这么高),空间 O ( n ) O(n) O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值