问题描述:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
输入:
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
输出:
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
样例输入:
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
样例输出:
2
1
题目解析:见代码注释。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n, k;
char a[10][10];
int visited[10];//visited数组记录在前h-1行第几列已经放入棋子了
int cont = 0;//cont代表种数
int way = 0;
void dfs(int h)//h代表行数 way代表选择放入棋子的个数
{
if (way == k)//当放入的棋子数等于给定需要放入的棋子数时 方案数加1
{
cont++;
return;
}
if (h >= n)//当所搜索的行数大于棋盘时 直接返回
return;
for (int i = 0; i < n; i++)//在第h行中从第一个位置开始列举
{
if (!visited[i] && a[h][i] == '#')//当前h-1行中第i列中已经放入了棋子 那么第h行就不用放了 因为棋子不能放在同一行 同一列
{
visited[i] = 1;
way++;
dfs(h + 1);
visited[i] = 0;//还原 假如第0行有两个# 当从第0行的第一个#开始往下走时,假设第2行中有且只有一个#,并且不与第一行中的任意一个在同一列,那么在往下
way--;//走时就会把这个#标记 当递归返回到第一行第一个#时 i会++ 到第一行的第2个# 函数继续会继续往下走 ,到达第2行的那个#,因为在第一行第一个#那条路径中
//已经走过了第2行的那个#(因为第2行只有一个#并且这个#所在的列数不与第一行两个#重合),如果不把第一次走过第二行的#的标记消除 那么这次路径就不会再过第二行的
//这个# 那么可选路径少了 肯定不对了
}
}
dfs(h + 1); //若改行没有可以放的位置那么就找下一行
}
int main() {
while (cin >> n >> k) {
if (n == -1 && k == -1)
break;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> a[i][j];
dfs(0);
cout << cont << endl;
memset(visited, 0, sizeof(visited));
cont = 0;
way = 0;
}
}