棋盘问题
Description
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
每组数据的第一行是两个正整数,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
思路: 因为 k <= n; 所以这个题与八皇后还是有差别的,当 k小于n 的时候,供摆放的棋子数小于行数,这里采用的思路是倒着放棋子,即第一行放第k个棋子,
当剩余行数大于剩余棋子数时,当前第cur个棋子有多种摆放,它可以放第row行,也可以放第row+1行或row+2行,直到剩余行数小于剩余棋子数;
1 //回溯/dfs/八皇后问题 2 #include<iostream> 3 #include<string.h> 4 using namespace std; 5 6 int n,k,ans; 7 char map[10][10]; 8 int vis[10];//标记某列是否被访问 9 10 void dfs(int row,int cur) 11 { 12 if(cur == 0)//递归边界,当所有棋子都放在合法位置,计数加1, 13 { 14 ans++; 15 return; 16 } 17 if(n-row+1 < cur) return;//当剩余行数小于剩余棋子数时显然不能合法的放完所有棋子,则退出 18 else dfs(row+1,cur);//当剩余行数大于剩余棋子数时,则继续向下一行递归。 19 20 if(cur > 0) 21 { 22 for(int i = 1; i <= n; i++) 23 { 24 if(map[row][i] == '#' && !vis[i])//若找到合法的列 25 { 26 vis[i] = 1;//标记该列已被访问 27 dfs(row+1,--cur);//继续递归 28 //递归出口修改初始值 29 vis[i] = 0; 30 ++cur; 31 } 32 } 33 } 34 } 35 int main() 36 { 37 while(cin>> n>> k) 38 { 39 if(n == -1 && k == -1) break; 40 for(int i = 1; i <= n; i++) 41 for(int j = 1; j <= n; j++) 42 cin>>map[i][j]; 43 memset(vis,0,sizeof(vis)); 44 ans = 0; 45 dfs(1,k);//从第一行开始递归,让第一行摆放第k个棋子 46 cout<<ans<<endl; 47 } 48 return 0; 49 }