DFS(棋盘问题)
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放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
首先这个题是真的66666666哈哈哈,像我这么弱的,竟然彻底明白了dfs哈哈哈,感谢上天,感谢宇宙,感谢我的室友哈哈哈,通过给她讲彻底明白了这个哈哈哈。调试是个好东西,模拟也是个好东西哈哈哈。
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
int k,n;
int sum;//方案数
char mp[10][10];//地图
int mark[10];//标记数组,看某一列有没有放入棋子,有就为1,没有就是0
void dfs(int temp,int cnt)//temp是第n行,然后cnt是当前棋子的数目
{
if(cnt==k)//如果走完之后等于棋子的数目,就直接退出,方案加1
{
sum++;
return ;
}
if(temp>=n)//如果行数超出范围,退出。
{
return ;
}
for(int i=0;i<n;i++)//这里的i是列数,
{
if(mp[temp][i]=='#'&&mark[i]==0)//如果这个是棋盘并且当前列没有放棋子
{
mark[i]=1;//就放棋子,标记该列走过
dfs(temp+1,cnt+1);//进行下一行的搜索
mark[i]=0;//这儿是最有意思的哈哈哈,看下面。
}
}
dfs(temp+1,cnt);
}
int main()
{
//int n,k;
while(~scanf("%d%d",&n,&k)&&(n!=-1)&&(k!=-1))
{
memset(mark,false,sizeof(mark));//标记数组清零
sum=0;//方案清零,因为sum定义的是全局,所以就需要清零
getchar();//吸收回车
for(int i=0;i<n;i++)
{
scanf("%s",mp[i]);
}
dfs(0,0);
printf("%d\n",sum);
}
}
至于那儿为啥又重新赋0了哈哈哈 好神奇,反正我是那么感觉。
首先,你得先明白啥是dfs,它的具体内涵,哈哈哈。
以以下样例为例
4 4
###.
#..#
####
.###
首先根据我们的代码,第一个方案就是
## # .
#. . #
####
.###
这个很好理解哈
然后出现了什么呢?
此时temp到了4 return了
然后回到了开始时候的那一步,也就是for循环里的dfs,接下来就是要进行对此时的i列清空标记,为什么?就是因为要回到第三行重新进行搜索。
然后i此时其实是2,继续加1,不行,已经走过了,然后退出for循环进行下一次的dfs 此时temp为4,返回
然后继续回到了第二行,此时i是1,i+1,可走,ok,下一个dfs,然后就重新开始for循环,到i等于1的时候可行,放入棋子,此时temp为4,cnt为4,方案加1。然后又返回到了第三行,继续第四行的i等于2,i=3,都不可行,然后就继续这样跑跑跑,跑到最后……
呐呐,明白了吧,嘿嘿嘿。
其实画个树状图挺好理解的,但是我不会画,在电脑上,嗐,打扰了,我还很弱……呜呜呜……
其实也很好理解的,只要自己调试一遍肯定就彻底明白了。
继续加油嘿嘿嘿