A - 棋盘问题
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
Sample Output
2
1
搜索路径 ::
1.棋子第一行进行遍历,j=0
标记第一行,当前摆放棋子数目way==1,
1.2.棋子第二行进行遍历,j=1
标记第二行,当前摆放棋子数目way==2,
way==K,return
清除第二行标记,摆放棋子数目way--,way=1
1.3棋盘第三行开始遍历,j=2
标记第三行,当前摆放棋子数目way==2
way==K,return
清除第三行标记,摆放棋子数目way--,way=1
1.4 标记第四行,当前摆放棋子数目way==2
way==K,return
清除第四行标记,摆放棋子数目way--,way=1
1系列完全遍历,第一行进行清除标记,way--,way==0
---每次遍历完全后,最后一行的DFS来开启下一行的遍历
由最后一行DFS进入2.系列--类似以上过程
参考网址 ::
https://blog.youkuaiyun.com/pit3369/article/details/68926243
方法一::
这种方法是用二维数组存储,二位数组存的时候是按字符串存储的,所以,在第一行输入n和k的值后,后面的回车要读走,不然影响后面字符的读入,而且每读完一行字符后,行的结尾的回车要读走,不然影响下一行的读入,这是特别要注意的。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
char mp[10][10];
int vis[100];
int n,k;
int way;//表示走的步数
int cnt;//记录个数
void dfs(int p){
if(way==k){ //当走的步数,即棋子的个数达到题目让放的数目的时候,就是一种情况,个数加1,然后返回上一层
cnt++;
return ;
}
if(p>=n){ //当遍历的行数大于数组的行数的时候,就结束
return ;
}
for(int j=0;j<n;j++){
if(vis[j]==0 && mp[p][j]=='#'){
way++;
vis[j]=1;//标记
dfs(p+1);
//遍历失败或者棋子数满足了
way--;
vis[j]=0;//清除标记
}
}
dfs(p+1);//该行已经满足棋子总数,所以K行不放棋子
}
int main(){
int i,j;
while(scanf("%d%d",&n,&k)!=EOF){
getchar();
way=cnt=0;
if(n==-1 || k==-1){
break;
}
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(i=0;i<n;i++){
for(j=0;j<n;j++){
scanf("%c",&mp[i][j]);
}
getchar();
}
dfs(0);
cout<<cnt<<endl;
}
}
方案二:::
这个方法的读入是用字符串读入的,所以再付一行输入n和k的值后,不用getchar(),把后面的回车读走。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
char mp[10][10];
int vis[100];
int n,k;
int way;//表示走的步数
int cnt;//记录个数
void dfs(int p){
if(way==k){ //当走的步数,即棋子的个数达到题目让放的数目的时候,就是一种情况,个数加1,然后返回上一层
cnt++;
return ;
}
if(p>=n){//当遍历的行数大于数组的行数的时候,就结束
return ;
}
for(int j=0;j<n;j++){
if(vis[j]==0 && mp[p][j]=='#'){
way++;
vis[j]=1;
dfs(p+1);
way--;
vis[j]=0;
}
}
dfs(p+1);
}
int main(){
int i,j;
while(scanf("%d%d",&n,&k)!=EOF){
way=cnt=0;
if(n==-1 || k==-1){
break;
}
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(i=0;i<n;i++){
scanf("%s",mp[i]);
}
dfs(0);
cout<<cnt<<endl;
}
}
方法三:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=20;
char g[maxn][maxn];
int n,k,num,ans;
int vis[maxn];
void dfs(int step)
{
if(num==k)
{
ans++;
return ;
}
if(step>=n)
{
return ;
}
for(int i=0;i<n;i++)
{
if(vis[i]==0 && g[step][i]=='#')
{
vis[i]=1;
num++;
dfs(step+1);
vis[i]=0;
num--;
}
}
dfs(step+1);
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
ans=0;
getchar();
int sum=0;
if(n==-1 && k==-1)
{
break;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%c",&g[i][j]);
if(g[i][j]=='#')
sum++;
}
getchar();
}
if(k>sum)
{
printf("0\n");
}else
{
num=0;
memset(vis,0,sizeof(vis));
dfs(0);
printf("%d\n",ans);
}
}
return 0;
}