POJ 1321 - 棋盘问题 - [经典DFS]

题目链接:http://poj.org/problem?id=1321

Time Limit: 1000MS Memory Limit: 10000K

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

 

可以说是非常经典的一道DFS题目了,不说有多难,但是可以很好地体现出DFS的思想。

 

对于一个n*n的棋盘,我们考虑按行进行DFS,一行一行往下推进就类似于DFS一层一层往下搜索。

对于函数dfs(int row,int num),row表示当前进行到哪一行,num代表到目前为止,棋盘上已经放了多少棋子了。

那么,在dfs()这个函数中,显然要对row这行上的每一格进行一次遍历(一次for循环);

遍历的过程中,遇到能放棋子的格子(两个要求:①这一格确实是属于棋盘的 map[i][j]='#' ;  ②这一列上,上面那几行没有放过棋子 vis[col]==0 ),那就不管了,先放上去再说;

那么我们放了一颗棋子之后,这行就不能再放了,那就往下走一行dfs(row+1,num+1);

那么我们dfs(row+1,num+1)这个做完了之后呢?

显然,我们又不是一定要往这个格子上放旗子,棋盘这么大我想去看看,所以我们要把之前放下的那颗棋子拿起来,继续在row这行上继续遍历,寻找下一个能放棋子的格子;

 

最后我如果把这一行全部遍历完了呢?我们是不是非得往这行上放棋子?

当然不是啦

如果棋子少,这行不放也是可以的呀,所以在一次for循环结束之后,我们也要往下一行走,即dfs(row+1,num)。

 

这就是大体上的DFS思路啦,更多细节请详见代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 char map[11][11];
 4 int n,k,ans;
 5 bool colvis[11];
 6 void dfs(int row,int num)
 7 {
 8     if(num==k)//全部chess都已经放完啦! 
 9     {
10         ans++;//方案数+1
11         return;
12     }
13     if(row>n) return;
14     for(int col=1;col<=n;col++)
15     {
16         if(map[row][col]=='#' && !colvis[col])
17         {
18             colvis[col]=1;
19             dfs(row+1,num+1);
20             colvis[col]=0;
21         }
22     }
23     dfs(row+1,num);
24 }
25 int main()
26 {
27     while(scanf("%d%d",&n,&k) && n!=-1)
28     {
29         memset(colvis,0,sizeof(colvis));
30         memset(map,0,sizeof(map));
31         for(int i=1;i<=n;i++) scanf("%s",map[i]+1);
32         ans=0;
33         dfs(1,0);
34         printf("%d\n",ans);
35     }
36 }

 泼妇爱科特!!!

posted @ 2017-07-29 17:14  Dilthey  阅读(333)  评论(0编辑  收藏  举报