摆棋子
题意:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放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
思路分析:
DFS方法。
1、从第一个棋子开始放,能放的棋子必须满足条件:在棋盘区域&&这个位置没被放过,按照这个条件把棋子依次放下去,每放一颗棋子记得:
(1)标记这个位置
(2)已放棋子数要加加
2、一旦遇到放不下去的棋子,就回溯到上一个棋子。此时:
(1)撤销上次被标记的位置
(2)已放棋子数要减减
3、判断越界是否可以结束。越界条件:
(1)已放棋子数=要求放的棋子数
(2)棋子数超过了棋盘区域
源代码:
1 #include<iostream> 2 #include<string> 3 #include<cstring> 4 using namespace std; 5 char chess[12][12]; 6 int vis[12]; 7 int n,k,sum,ans; 8 void dfs(int a) 9 { 10 11 if (ans == k) //已放棋子数=给定的棋子数 12 { 13 sum++; 14 return; 15 } 16 if (a >= n) //棋子数超过棋盘区域 17 return; 18 19 for (int j = 0; j < n; j++) 20 { 21 if (chess[a][j] == '#'&&!vis[j]) 22 { 23 vis[j] = 1; //标记位置已被放过 24 ans++; //已放棋子数加加 25 dfs(a + 1); //放下一个棋子 26 vis[j] = 0; //撤销标记,递归失败 27 ans--; //已放棋子数减减 28 } 29 30 } 31 dfs(a + 1); //放第二行棋子 32 } 33 int main() 34 { 35 while (cin >> n >> k) 36 { 37 sum = 0; //方案数 38 ans = 0; //已放棋子数 39 getchar(); 40 if (n == -1 && k == -1) 41 break; 42 memset(chess, 0, sizeof(chess)); 43 memset(vis, 0, sizeof(vis)); 44 for (int i = 0; i < n; i++) 45 { 46 for (int j = 0; j < n; j++) 47 cin >> chess[i][j]; 48 getchar(); 49 } 50 dfs(0); 51 cout << sum << endl; 52 } 53 54 return 0; 55 56 }
心得:
本题跟八皇后的问题相似,都是DFS,回溯,但是有些细节不一样,比如越界条件。第二次遇到这种题目还是有些恍惚,可能是没有理解透吧。。。。。↖(^ω^)↗加油
------------------------
没有谁的人生不是斩棘前行
----------------------------------------
JM