棋盘问题

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

思路: 因为 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 }
View Code
原文地址:https://www.cnblogs.com/LK1994/p/3224287.html