Description
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
Sample Output
2 1
思路
这题和N皇后有点相似,但还是有不同点:
N皇后还要求对角线和辅对角线都不能放,需要使用额外数组去判断对角线和辅对角线有没有放过棋子
N皇后初始化时每个位置只有一种状态,而这题初始化时每个位置有'#'和'.',只有'#'才可以放搜索的结束条件为:已经放好的棋子数量等于k,方案数加一
当前行数等于n,因为从索引为0的行开始找,当前行数等于n,也就说明0~n-1行都遍历了在dfs函数的最后面要加上 dfs(u + 1, cnt);
因为有可能在搜索某一行时,这一行的每个位置都是’.’,也有可能除了’.'外的其他位置所在的列都放了棋子,
如果没有上面这行代码,就有可能无法进到下一行去搜索
C++ 代码
#include<iostream>
#include <algorithm>
#include<cstring>
using namespace std;
const int N =10;
int n,k,ans;//n为棋盘的行数和列数,k为要放的棋子数量,ans为方案数,cnt为已经放了多少个棋子
char g[N][N];//存储地图
bool col[N];//记录某一列是否已经放了棋子
void dfs(int u,int cnt) {
if(cnt == k) {//如果放了的棋子数量等于k,则添加一个方案
ans++;
return;
}
if(u == n) return;//因为从索引为0的行开始找,当u等于n,也就说明0~n-1行都遍历了
for(int i=0; i<n; i++) {
if(g[u][i]=='#'&&!col[i]) {
col[i]=true;
dfs(u+1,cnt+1);
col[i]=false;//回溯
}
}
dfs(u+1,cnt);//注意这行代码
}
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 >> g[i][j];
ans = 0 ;
memset(col,false,sizeof(col));
dfs(0,0);
cout << ans << endl;
}
}