Description
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。
要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列。请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n,k,用一个空格隔开,表示了将在一个n∗n的矩阵内描述棋盘,以及摆放棋子的数目。
当为−1 −1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C。
Sample Input 1
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
Sample Output 1
2
1
Hint
n<=8,k<=n
数据保证C <2^31
Time Limit
1000MS
Memory Limit
256MB
分析:题意为求所有棋子摆放方案数,可知此题用深搜。撰写搜索代码的关键,在于理清楚搜索的单位,即空间状态——能区分出每个结点的因素、进行搜索的逻辑在数据上的体现。此题中空间状态不妨设为:摆放在棋盘第几行、还有几个棋子未摆放。同时,此题的特别之处在于棋盘上的一行或多行可以不摆棋子,这时的空间状态只变化行数,不变化剩余棋子数。
参考代码:
#include<stdio.h>
int n,k;//棋盘尺寸,棋子数目
int ans;//摆放方案数
char map[9][10];//描述棋盘的内容
bool vis[9];//记录棋盘里已经被占用的列
//当前摆放棋盘第几行,当前还有几个棋子未摆放
void dfs(int now,int last)
{
if(last==0){//没有剩余棋子,都摆放完了
ans++;//找到一种摆放方案
return;
}
if(now>n){//当前方案不合法,回退,重新搜索
return;
}
//按列枚举
for(int j=1;j<=n;j++)
{//是空白区域或者已经被占用
if(map[now][j]=='.'||vis[j]) continue;
vis[j]=true;//标记
dfs(now+1,last-1);//摆下一行,棋子数减1
vis[j]=false;//回溯
}
//这一行没有摆棋子,到下一行去摆
dfs(now+1,last);
return;
}
int main()
{
while(1)
{
scanf("%d%d",&n,&k);
if(n==-1&&k==-1) break;
for(int i=1;i<=n;i++)
{
scanf("%s",&map[i][1]);
}
ans=0;//答案清零
for(int i=0;i<9;i++)
{//标记数组也清零
vis[i]=0;
}
dfs(1,k);//开始搜索
printf("%d\n",ans);
}
return 0;
}