Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 27733 | Accepted: 13699 |
Description
Input
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
Sample Input
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
Sample Output
2 1
题目链接: POJ 1321 棋盘问题
DFS~这题也比较简单。第一眼读题瞬间想到了八皇后
题目是中文的,不是很难理解。思路如下:
我定了2个数组。一个存棋盘,另一个一维数组vis用于保存该列是否被访问,也就是说该列是否能放棋子
dfs(int line,int num),传的是第几行和第几个棋子。
如果num==k,说明都放完了。那么return,结果+1~接下来是dfs过程
我们for循环列数。如果当前位置是#,并且该列可以放棋子(即vis[j]!=1),那么我们就可以把棋子放在这里了,把该列设为已访问,然后继续dfs放下一个棋子,记得回溯之后把vis[j]还原为0.不然就没法再找下一种摆法啦!
否则的话,说明这行是放置不了棋子的。我们dfs(line+1,num),也就是说把这个棋子带到下一行去看能不能放。
注意的是,如果line都搞到了大于n了,就跑到棋盘外面去了。直接return终止dfs~
主函数里面dfs(1,0),其实这里我自己有点没太明白,刚开始写的dfs(1,1),但是答案是错的。改成(1,0)就对头了。
棋盘用的是cin,这种带字符的东西用scanf %c容易出事-。-经常吞个回车啊之类的,现在除了很简单的需要%c的,其他时候基本就是%s或者cin。一用%c心里慌的要死- -还是cin比较一劳永逸。但是cin cout比较慢,尽量还是scanf printf比较好,尤其是在比赛的时候,基本都不cin cout。不过还有一点,就是cin cout和scanf printf这两种混合使用的时候,好像有的时候会出事。因为之前看过一个题解,有个同学说他们当时比赛这两种混合用的,结果出问题了,还好组委会给了PE,他们改了一下就过了。如果给的是WA估计这辈子都想不出那错了- -虽然不知道会不会真的出事,不过还是稳妥一点比较好。下面是AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char maze[9][9];
bool vis[9]; //表示该列是否有棋子。
int n,k,c;
void dfs(int line,int num)
{
if(num==k) //num=k时return,种类+1
{
c++;
return;
}
if(line>n) //行超出边界 退出dfs。
return;
for(int j=1;j<=n;j++)
{
if(maze[line][j]=='#' && vis[j]!=1) //如果能放棋子,并且该列可以放棋子
{
vis[j]=1; //该列设为已放棋子
dfs(line+1,num+1); //,接下来放下一个棋子
vis[j]=0; //回溯后还原为0,用于继续下一种摆放。
}
}
dfs(line+1,num); //如果棋子在该行不能摆放的话,到下一行去看是否能摆放。
return;
}
int main()
{
while(cin>>n>>k)
{
c=0;
if(n==-1||k==-1)
break;
else
{
memset(vis,0,sizeof(vis)); //初始化
memset(maze,0,sizeof(maze)); //初始化
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>maze[i][j]; //输入棋盘
dfs(1,0);
cout<<c<<endl;
}
}
return 0;
}