zoukankan      html  css  js  c++  java
  • ACwing843

    n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

    在这里插入图片描述

    现在给定整数n,请你输出所有的满足条件的棋子摆法。

    输入格式

    共一行,包含整数n。

    输出格式

    每个解决方案占n行,每行输出一个长度为n的字符串,用来表示完整的棋盘状态。

    其中”.”表示某一个位置的方格状态为空,”Q”表示某一个位置的方格上摆着皇后。

    每个方案输出完成后,输出一个空行。

    输出方案的顺序任意,只要不重复且没有遗漏即可。

    数据范围
    1 ≤ n ≤ 9

    输入样例:

    4

    输出样例:

    .Q…
    …Q
    Q…
    …Q.

    …Q.
    Q…
    …Q
    .Q…

    题目大意:

    要求输出方案数,有n * n 的棋盘,需要放n皇后(用Q表示),空地用’ . ’ 表示,关于皇后放置有以下几个要求:

    • 任意两个皇后不能在同一行
    • 任意两个皇后不能在同一列
    • 任意两个皇后不能再同一对角线

    要求输出摆好的棋盘。

    解题思路:

    经典n皇后问题,用dfs解决,数据范围很小,dfs暴搜 + 剪枝即可AC,这里介绍两种搜索思路:

    思路一:从第1行搜索到第n行, 按列判断。
    这个思路是按行搜索,标记每一列和主次对角线,按行搜索可以保证任意两个皇后都不在同一行,然后去搜这一行的1 - n 列,开标记数组book标记这一列上是否有皇后,gh和ugh标记主次对角线,关于主次对角线:

    • y = - x + b 对于每一个点(y + x)都有唯一的 b 值对应
    • y = x + b 对于每一个点(y - x) 有唯一的b 值对应

    因为第二个涉及到了y - x有可能负数,所以开大一点标记数组,并把式子映射为y - x + n 。因为都有唯一一个 b 所对应,所以可以根据 x ± y 的值是否被标记过判断该对角线上有无皇后,之后按照dfs模板去搜,状态改变状态还原,如果x > n 则证明搜完了且一定存在解(因为继续往下搜索的前提是这一行可以找到放皇后的位置),输出并return;

    Code1:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <iomanip>
    #include <sstream>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <unordered_map>
    #include <unordered_set>
    #define lowbit(x) x & (-x)
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    const int N = 25;
    
    int n;
    char mp[N][N];
    bool gh[N], ugh[N], book[N];
    
    void dfs(int s)
    {
        if (s == n + 1)
        {
            for (int i = 1; i <= n; i ++) puts(mp[i] + 1);
            puts("");
            return;
        }
    
        for (int i = 1; i <= n; i ++)
        {
            if (!book[i] && !gh[s + i] && !ugh[n + s - i])
            {
                book[i] = true;
                gh[s + i] = true;
                ugh[n + s - i] = true;
                
                mp[s][i] = 'Q';//改状态并继续搜
                dfs(s + 1);
                
                book[i] = false;
                gh[s + i] = false;
                ugh[n + s - i] = false;
                mp[s][i] = '.';//还原状态
            }
        }
    
        return;
    }
    
    int main()
    {
        scanf("%d", &n);
    
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                mp[i][j] = '.';
        
        dfs(1);//从第一行开始搜
        
        return 0;
    }
    

    思路二:枚举所有格子的状态
    顾名思义:每个格子有放和不放两种状态,对于每个格子枚举即可。每次枚举完以后枚举(x, y + 1, s),如果y > n 说明这行枚举完了,y = 1, x++, 继续枚举下一行,如果x > n 则说明整个棋盘枚举完了,判断s 是否等于 n ,这里的 s 是指当前已经放下了几个皇后,如果等于n则输出棋盘,之后return。

    每个格子只有放和不放,不放的话很好理解,直接dfs(x, y + 1, s),如果放的话需要判断一下这个格子是不是能放皇后,需要开一个行标数组,列标数组,主次对角线,都判断一下,然后选择是否放皇后即可。

    Code2:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <iomanip>
    #include <sstream>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <unordered_map>
    #include <unordered_set>
    #define lowbit(x) x & (-x)
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    const int N = 25;
    
    int n;
    char mp[N][N];
    bool gh[N], ugh[N], col[N], row[N];
    
    void dfs(int x, int y, int s)
    {
        if (y > n)
        {
            y = 1;
            x++;
        }
        
        if (x > n)
        {
            if (s == n)
            {
                for (int i = 1; i <= n; i ++) puts(mp[i] + 1);
                puts("");
            }
            return;//return一定要写在 if 外面,因为不管方案是否可行都搜完了要返回,不然会MLE。
        }
    
        dfs(x, y + 1, s);
        
        if (!row[x] && !col[y] && !gh[x + y] && !ugh[x - y + n])//判断是否可以放皇后
        {
            row[x] = col[y] = gh[x + y] = ugh[x - y + n] = true;//行标列标主次对角线都判断一下
            mp[x][y] = 'Q';//状态修改/还原
            dfs(x, y + 1, s + 1);
            row[x] = col[y] = gh[x + y] = ugh[x - y + n] = false;
            mp[x][y] = '.';
        }
    
        return;
    }
    
    int main()
    {
        scanf("%d", &n);
    
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                mp[i][j] = '.';
        
        dfs(1, 1, 0);//从(1, 1)开始搜,当前已经放了0个皇后
        
        return 0;
    }
    
  • 相关阅读:
    洛谷 P1850 换教室(期望dp)
    简单异或 && 洛谷 P1469 找筷子 && 洛谷 P3908 数列之异或
    2020 CSP-J复赛题解
    2018 ICPC 南京 D Country Meow(模拟退火|三分)
    佩尔方程
    块速幂/光速幂
    1436F
    反Nim游戏
    P1447 [NOI2010]能量采集(莫比乌斯反演)
    P3768 简单的数学题 (莫比乌斯反演+杜教筛)
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294142.html
Copyright © 2011-2022 走看看