【问题描述】
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
【输入格式】
第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
【输出格式】
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
【输入样例】
【样例1】
2 1
#.
.#
【样例2】
4 4
…#
..#.
.#..
#…
【输出样例】
【样例1】
2
【样例2】
1
【样例解释】
时间限制:1秒 内存限制:64M
【数据范围】
n <= 8 , k <= n
【问题分析】
看到这道题,很自然而然地就会联想到回溯的一道经典题——n皇后问题。所以解法类似,从第一行开始搜索,对于每一列设标记数组c[j]表示是否放过棋子。然而这道题最大的区别就是对于棋子个数有限制!!也就是说,不是每一行都放了棋子。
1.分步:共n行,最多分为n步
2.每步的选择:从1~n列中选择‘#’的位子
3.约束条件:对于每一列,需要c[j]没有棋子
4.选择后处理:run(t+1),若t>n则return
5.求解:当所有棋子放完——num==k,cnt++
TIP:因为要讨论所有棋子的所有可能性,因此run的最后需要再对剩下的棋子进行的一次遍历。原因即因为棋子数量有限,每一行不一定必须放旗子,所以要讨论其他情况!!!
【核心代码】
int s,n,k,cnt=0;
char Map[9][9];
int c[10];//每一列
void run(int t)//t行第s个
{
if(s==k)
{
cnt++;
return;
}
if(t>=n)return;
for(int i=0;i<n;i++)if(Map[t][i]=='#')//枚举每一列
{
if(c[i]==0)
{
c[i]=1;
s++;
run(t+1);
c[i]=0;
s--;
}
}
run(t+1);//进行剩下的k-1个棋子的遍历
}
Written By Mr_Shadow from CQYZ