棋盘问题
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 20000/10000K (Java/Other)
Total Submission(s) : 97 Accepted Submission(s) : 30
Problem Description
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。<br>每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n<br>当为-1 -1时表示输入结束。<br>随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。<br>
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
Sample Output
2 1
题意是给n*n的棋盘并给出棋盘的形状,要求放k个棋子,每一行或列都只能有一个。
开始我搜索的方向是对每一个可以放棋子的点都进行广度搜索,每次到k个棋子后方案数加1,最后方案数除以k得结果,按我所想的,由于会有重复,而又因为每一种情况有k个棋子,所以除以k就可以吧重复去掉。写出来之后发现还是很大的结果,也就是依然有重复方案,想要去掉也没想出来办法,应该是思路本身就错了。
正确思路的话,是对每一行(列)进行广搜,对该行的点判断放棋子,在放完棋子后标记,放满k个是方案数加1。
代码如下:
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
int n,k;
int a[20][20];
int yy[20];
int t;//已放旗子
int sum;//方案数
void ioan(int x)
{
if(t == k)//放了 k个棋子
{
sum++;
return ;
}
if(x>n)//行数越界
{
return ;
}
//如果第 i行要放的话 考虑下面:
for(int i = 1; i <= n; i++)//对列 i
{
if(yy[i] == 0 && a[x][i] == 0)// i列 没有放过
{
yy[i] = 1;//标记 i列
t++;//
ioan(x+1);
yy[i] = 0;//回溯
t--;
}
}
//如果 i行不放,直接下一行
ioan(x+1);
return ;
}
int main()
{
//freopen("D:\\aaa.txt","r",stdin);
//freopen("D:\\bbb.txt","w",stdout);
while(cin >> n >> k)
{
if(n==-1&&k==-1)
break;
memset(yy, 0, sizeof(yy));
char ch;
for(int i = 1; i <= n; i++)
{
for(int j = 1;j <= n; j++)
{
cin >> ch;
if(ch=='#')//棋盘区域
a[i][j] = 0;
else
a[i][j] = 1;
}
}
t = 0;
sum = 0;
ioan(1);//对行
cout << sum << endl;
}
return 0;
}