L - 棋盘问题
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1Sample Output
2 1
题意及要求:给了我们一个棋盘,其中'#'代表能放棋子的地方'.'则表示不能放棋子的地方,然后要把k个棋子放入棋盘,使得每行每列有且仅有一个棋子.求有多少种这样的方法满足题意.
分析:需要得出方法数,每次这个方法从棋盘放置中得出,并且方法可行性也从棋盘放置这里得出,那么要怎么放置呢.
从左上角到右下角每个都试一试,如果使得k个棋子刚好放下,并且每行每列有且仅有一个棋子,那么方法数就+1;
那么就用dfs()了,那么dfs(参数) 参数是什么?
来分析一下,从左上角到右下角,放置棋子时 改变的自然就是k 棋子的个数.
同时,左上角到右下角变化的时候,行数也在改变.当然列数也在改变.还有就是方法数.
但,当且仅当满足时,方法数+1.所以不用后退继续寻找.
那么现在就是三个变量,行数,列数和棋子个数.
那么要怎么处理呢.
究竟要怎么搜索.
双层foe循环,从左上角到右下角.那么!!!,并且每行每列有且仅有一个棋子 这个要求要怎么处理.
放置一个棋子,那么那一列或者一行都无法再放置.如果可放置,那么vis=0;反之vis=1.
那么vis如果要用二维的,处理起来会有点麻烦.
所以要用一个巧妙的办法
我们从左上角移到右下角,行数变化了,因为有且仅有一个棋子,那么行数自上而下,也不用做什么处理.所以只要考虑列数,那么我们用vis存储列数.
此时列数已经有vis来控制,那么原来的三个参数自然就只剩两个了.
下面就上代码吧,千万句话来解释也不如一句代码.
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
int n,k,ans;
string s[100];
int vis[100];
void dfs(int row,int kk)
{
if(kk==0)
{
ans+=1;
return ;
}
for(int i=row;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(s[i][j]=='.'||vis[j]==1) continue;
vis[j]=1;
dfs(i+1,kk-1);
vis[j]=0;
}
}
}
int main()
{
while(cin>>n>>k)
{
if(n==-1&&k==-1) break;
ans=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<10;i++)
s[i].clear();
for(int i=0;i<n;i++)
{
getchar();
cin>>s[i];
}
dfs(0,k);
cout<<ans<<endl;
}
}
ps:2018年4月10日 13:05:08
昨晚第二次做这个题目,没有仔细思考,直接敲代码,以至于后来全是bug,然后边看博客边找自己的bug.
记得第一次做这个题目的时候也是这样.
果然,做个每个题目,不管简单还是难,都一定要给自己一点思考时间,要有自己的思维,否则就算此次做出来了,下次换汤不换药的随便改一改,就不会了.
因此不能在这么一味追求速度了,也要保证质量.!!!