这道题目是典型的深搜题,以前做过的题目是给定一个矩阵棋盘,要求每一行每一列只能安排一个棋子,且安排的棋子数即为行数,这题要相对复杂一些,有如下不同点:
1)棋盘是嵌在矩阵中的,不是单纯的矩阵
2)要求安排的棋子数<=矩阵的行数
主要的难点在于第二个不同点。要枚举所有的可能还是比较费时的,所以要用到剪枝。
那么主要思路就是利用深搜枚举所有可能情况,枚举的关键是后续棋子放置的行号要小于当前已经安排棋子的行号,这样才不会造成重复枚举。同时要注意回溯和剪枝。
回溯的关键就是将已经安排棋子的列号枚举完后,设置该列号为可放置。
剪枝的关键在于:当前可放棋子的行数要大于或等于要放置的棋子数-已经放置的棋子数,这里假设每行至少可以放置一个棋子(实际上有可能不能实现)
下面的题目实际上是该题的一种特殊情况:
给定一个矩阵棋盘n*m,和要放置的棋子数k(k<=n),要求每一行每一列只能放置一个棋子,问有多少种放置方案。
下面是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 10
bool flag[Max][Max];
bool vi[Max];
int n,k;
__int64 count;
void dfs(int level,int num){
if(num==k){
count++;
return ;
}
for(int i=level-1;i>=k-num;i--)
for(int j=1;j<=n;j++)
if(flag[i][j] && !vi[j]){
vi[j]=1;
dfs(i,num+1);
vi[j]=0;
}
}
int main(){
while(scanf("%d%d",&n,&k),n!=-1){
char str;
memset(flag,0,sizeof(flag));
memset(vi,0,sizeof(vi));
for(int i=1;i<=n;i++){
getchar();
for(int j=1;j<=n;j++){
str=getchar();
if(str=='#')
flag[i][j]=1;
}
}
count=0;
dfs(n+1,0);
printf("%I64d\n",count);
}
return 0;
}