#P1064. 2023.3.5-n皇后
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 645
            Accepted: 187
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              米哈游
                                
            
                        
              时间 :2023年3月5日
                              
                      
          
 
- 
                        算法标签>暴力枚举          
 
2023.3.5-n皇后
思路
暴力O(n3)不可取.我们先扫描一遍棋盘。用r,c 数组来统计第i行/第i列有多少个皇后。对于处于同一正副对角线的两点,有如下规律:
正对角线:两点的横纵坐标之差x-y相等.所以用x-y来对正对角线编号
副对角线:两点的横纵坐标之和相等.所以用x+y来对正对角线编号
所以再使用x,y 数组来记录第i个正负对角线的皇后个数。
预处理完之后,枚举每个点i,j , check一下r[i],c[j],x[i−j],y[i+j] 是不是全为0即可。 全为0就代表可行,然后计数。
最后,注意一开始局面就不合法的情况。这种情况需要输出0并提前结束程序!
代码
C++
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1005;
int a[maxn][maxn];
// 记录行,列,正负对角线的皇后个数
int c[maxn] , r[maxn] , x[maxn * 2] , y[maxn * 2];
int main()
{
    int n;
    cin >> n;
    bool ok = true;
    for (int i = 1 ; i <= n ; i++){
        string t;
        cin >> t;
        t = '#' + t;
        for (int j = 1 ; j <= n ; j++){
            if (t[j] == '*'){
                a[i][j] = 1;
                if (r[i] || c[j] || x[i - j + n] || y[i + j]){
                    ok = false;
                }
                r[i]++;
                c[j]++;
                x[i - j + n]++;
                y[i + j]++;
            }
        }
    }
    if (!ok){
        cout << "0" << endl;
        return 0;
    }
    int cnt = 0;
    for (int i = 1 ; i <= n ; i++){
        for (int j = 1 ; j <= n ; j++){
            if (a[i][j] == 1) continue;
            if (r[i] || c[j] || x[i - j + n] || y[i + j]) continue;
            cnt ++;
        }
    }
    cout << cnt << endl;
    return 0;
}
java
import java.util.*;
public class Main{
    public static void main(String args[]){
        queen();
    }
    public static void queen(){
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        scanner.nextLine();
        HashSet<Integer> row=new HashSet<>();
        HashSet<Integer> col=new HashSet<>();
        HashSet<Integer> dia1=new HashSet<>();
        HashSet<Integer> dia2=new HashSet<>();
        int c;
        for(int i=0;i<n;i++){
            String s=scanner.nextLine();
            c=s.indexOf("*");
            if(c!=-1){
                row.add(i);
                col.add(c);
                dia1.add(i+c);
                dia2.add(i-c);
            }
        }
        int count=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(row.contains(i)||col.contains(j)||dia1.contains(i+j)||dia2.contains(i-j)){
                    continue;
                }
                count++;
            }
        }
        System.out.println(count);
    }
    
}
python
import sys
'''
6
.*....
......
......
.....*
......
*.....
'''
def dataProcess():
    n = int(input())
    grid = []
    for i in range(n):
        temp = input()
        grid.append(list(temp))
    return n,grid
# I only add one queen for next backtracing operation
def nQueen(n, grid):
    c = [0] * n
    r = [0] * n
    x = [0] * 2 * n
    y = [0] * 2 * n
    a = [[0 for i in range(n)] for j in range(n)]
    ans = 0
    for i in range(n):
        for j in range(n):
            if grid[i][j] == "*":
                a[i][j] = 1
                r[j] += 1
                c[i] += 1
                x[i-j+n] += 1
                y[i+j] += 1
    for i in range(n):
        for j in range(n):
            if a[i][j] == 1:
                continue
            if c[i]!=0 or r[j]!=0 or x[i-j+n]!=0 or y[i+j]!=0:
                continue
            ans += 1        
    return ans
if __name__ == "__main__":
    n,grid = dataProcess()
    ans = nQueen(n, grid)
    print(ans)
js
const lines = [];
const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
(async () => {
  for await (const line of rl) {
    lines.push(line);
  }
  const n = parseInt(lines[0]);
  let res = 0;
  const grid = lines.slice(1).map(l => l.split(''));
  const preProcessing = () => {
    const col = new Map();
    const row = new Map();
    const diag1 = new Map();
    const diag2 = new Map();
    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n; j++) {
        if (grid[i][j] === '*') {
          col.set(j, true);
          row.set(i, true);
          diag1.set(i + j, true);
          diag2.set(i - j, true);
        }
      }
    }
    return [col, row, diag1, diag2];
  }
  const [col, row, diag1, diag2] = preProcessing();
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (!(col.get(j) || row.get(i) || diag1.get(i + j) || diag2.get(i - j))) {
        res += 1;
      }
    }
  }
  console.log(res);
})();
        题目内容
米小游是一个热衷于国际象棋的棋手,他最近在研究 n 皇后问题。在国际象棋中,皇后是一种强大的棋子,能够沿着横、竖、斜线攻击其他棋子。
而在 n 皇后问题中,皇后也是一种强大的棋子,它能攻击同一行、同一列以及同一 45 度角斜线和 135 度角斜线上的其他皇后。
米小游手上拿着一个 n×n 的棋盘,上面已经放置了一些皇后。他希望再放置一个皇后,使得所有的皇后不会互相攻击。
对于一个 n×n 的棋盘,有多种不同的摆放皇后的方式,而有些摆法可能会导致皇后之间发生攻击,有些摆法则不会。
因此,米小游需要找到所有满足条件的摆法,以便让他更好地研究 n 皇后问题,你能帮米小游求出有多少种放置方案吗?
输入描述
第一行输入一个正整数 n ,代表棋盘大小。
接下来的 n 行,每行输入一个仅由 . 和 ∗ 组成的字符串,其中 ∗ 代表放置了一个皇后, . 代表未放置皇后。
保证输入的棋盘中没有两个皇后会互相攻击。
1≤n≤1000
输出描述
输出米小游有多少种放置方案。
样例
输入
3
.*.
...
...
输出
2