Post

AcWing1114 - 棋盘问题

题设

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。

要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k个棋子的所有可行的摆放方案数目 C。

输入格式

输入含有多组测试数据。

每组数据的第一行是两个正整数 n,k,用一个空格隔开,表示了将在一个 n∗n 的矩阵内描述棋盘,以及摆放棋子的数目。当为-1 -1时表示输入结束。

随后的 n 行描述了棋盘的形状:每行有 n 个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

输出格式

对于每一组数据,给出一行输出,输出摆放的方案数目 C (数据保证 C<231)。

数据范围

n≤8,k≤n

输入样例:

1
2
3
4
5
6
7
8
9
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

输出样例:

1
2
2
1

题解

这是一个n皇后问题的变题,除了棋子不能放在同行同列的约束条件外,还有防止区域和数量的约束,但处理起来很简单。这里采用递归行的dfs算法,需要注意的是每次递归应分别递归这一行放了棋子和不放棋子的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <cstring>
using namespace std;
const int N = 10;

int n, k, cnt, res;
char g[N][N];
bool r[N];

void dfs(int u) {
  if (cnt == k) {
    res++;
    return;
  }
  
  if (u == n) return;
  
  for (int i = 0; i < n; i++) {
    if (g[i][u] == '#' && !r[i]) {
      cnt++;
      r[i] = true;
      dfs(u + 1);
      r[i] = false;
      cnt--;
    }
  }
  dfs(u + 1);
}

int main() {
  while (scanf("%d%d", &n, &k) && n > 0) {
    for (int i = 0; i < n; i++) scanf("%s", g[i]);
    
    memset(r, 0, sizeof r);
    cnt = 0, res = 0;
    
    dfs(0);
    
    printf("%d\n", res);
  } 
  return 0;
}
This post is licensed under CC BY 4.0 by the author.