第一题:
大家看完这两道题应该对棋盘问题有了一定认识,并且对dfs有了更加深刻的认识!耐心看完,我写的十分详细。
题目:
不爱看题目这里有链接
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。
要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k 个棋子的所有可行的摆放方案数目 C。
输入格式
输入含有多组测试数据。
每组数据的第一行是两个正整数 n,k,用一个空格隔开,表示了将在一个 n∗n 的矩阵内描述棋盘,以及摆放棋子的数目。当为-1 -1时表示输入结束。
随后的 n 行描述了棋盘的形状:每行有 n 个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
输出格式
对于每一组数据,给出一行输出,输出摆放的方案数目 C
输入样例:
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
输出样例:
2
1
题意分析:
给出n*n的棋盘,其中’#‘可以放,’.'不可以放,给出棋子个数k,我们要找出所有棋子摆放情况!这种题第一时间肯定想到的就是搜索!找出所有可能。这道题的思想和"全排列"是差不多的,我们可以利用dfs深度优先搜索,通过剪枝优化,枚举所有状态。
如何找出深搜的终点呢?如何剪枝优化呢?
首先棋盘为n*n,我们先讨论剪枝优化,很容易想到,当棋子越出棋盘,这种情况肯定要剪掉,或者遇到’.'的情况我们也剪掉,我们在讨论dfs终点,也就是深搜到底的情况,这里我们用last变量,表示棋子剩余数量,所以当last为0时,也就是所有棋子都摆放完毕,这就是深搜的终点!
如何枚举所有状态呢?
一个棋子肯定要放在某行某列,那么放在第几行第几列就是他的状态,在枚举状态过程中,我们可以固定行,然后枚举j列,每次dfs带入行数,在dfs过程中枚举所有可以放的列,要注意,某一行也可不放置棋子!!!
代码实现:
#include <iostream>
using namespace std;
const int maxn=10;
char maps[maxn][maxn];//棋盘
int visit[maxn];//是否被标记
int n,ans,k;
void dfs(int x,int last)//last 剩余棋子数量,x为行数
{
if(last==0)
{
ans++;
return;
}
if(x>n)//越界
{
return ;
}
//第i行插入棋子情况
for(int j=1; j<=n; j++)
{
if(maps[x][j]=='#'&&!visit[j]){
visit[j]=1