[DFS]-棋盘问题[详解]

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。

要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 kk 个棋子的所有可行的摆放方案数目 CC。

输入格式

输入含有多组测试数据。

每组数据的第一行是两个正整数 n,kn,k,用一个空格隔开,表示了将在一个 n∗nn∗n 的矩阵内描述棋盘,以及摆放棋子的数目。当为-1 -1时表示输入结束。

随后的 nn 行描述了棋盘的形状:每行有 nn 个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

输出格式

对于每一组数据,给出一行输出,输出摆放的方案数目 CC (数据保证 C<231C<231)。

数据范围

n≤8,k≤nn≤8,k≤n

输入样例:
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
输出样例:2 1

OK啊,先上代码,注释看不懂,再看详解:

#include <iostream>  
#include <vector>  
#include<iomanip>
#include<cstdio>
using namespace std;
const int N = 10;
int n, k;//定义棋盘n*n 与 棋子数
char g[N][N]; // 建立地图 题目<=8
bool qs[N];//列定义 注意类型 表示的是有无 放过棋子
int fan = 0;//方案数

void dfs(int x, int cnt) {
	if (cnt == k) {
		fan++; return; // 棋子达到K 说明放不下了 方案+1 退出搜索
	}
	if (x >= n) {
		return; // 行历遍完了 退出搜索 
	}
	//开始枚举-面向行的
	for (int i = 0; i < n; i++) {
		if (qs[i] == false && g[x][i] == '#') { //这列没放过棋子
			qs[i] = true;	//现在你放过了
			dfs(x + 1, cnt + 1); // 继续搜索下一行 cnt+1 为你放的棋子+1
			qs[i] = false;	//回溯
		}
	}
	dfs(x + 1, cnt);//上面的for循环可能会产生这一行的每一列内都无法放置的问题 所以需要强制进行下一行 , 保证每一行都可以历遍.
}
int main() { 
	while (cin >> n >> k, n > 0 && k > 0) {
		for (int i = 0; i < n; i++) {
			scanf("%s", g[i]);
		}//录入地图
		fan = 0;//初始化方案数
		dfs(0, 0);//从这个地图的第0行开始寻找,后面的0表示棋子数
		printf("%d\n", fan);//输出这个实例的方案数
	}
	return 0;
}

=========================详细解说=====================

1.根据题目要求,我们需要创建地图,在创建完地图之后,我们需要根据题意(多组数据)使用while来多次输入数据.

2.在录入地图完毕之后,我们初始化了方案数,因为题目要求的是每个实例最后都要输出方案数,所以我们需要在每次while循环内去初始化它,防止它自己出现累加的情况,导致输出错误.

3.dfs(0,0)传入了2个int 类型, 前者代表的是行 意思是从第0行开始寻找,这和dfs的内容是挂钩的,第二个则是以放置的棋子数量默认为0,因为你一个棋子都还没有放置.

4.打印输出换行结果.

Main部分结束 DFS部分开始:==========================

1.我们用2个if来控制DFS的结束,第一个if是与棋子数挂钩的,因为你退出了这一次搜索,而且你这个方案的要求放置的棋子也已经放完了,所以你需要对方案数++.

2.x>=n是为了放置历遍的行出界,为什么还要等于n是因为二维数组的行列都是以0开始记的.

3.然后我们对行开始枚举,如果它没有放置过棋子且它是“#”,前者我们用qs这个bool进行判断,注意,这个qs是直接对该列起作用的,因为题目要求就是 在这一行这一列只能放置一个棋子,而我们对行进行枚举所以对列可以进行整列视为一的看待.

4.当我们发现这个位置可以进行棋子的放置,于是把qs该列标记为true,表示这列的状态不能放了,同时进行dfs(x + 1, cnt + 1)的操作 x+1是表示x的下一行 cnt+1 是表示放置的棋子数+1 .

5.如果这一行没办法操作,我们就需要通过回溯的方法,重新把qs[i]定义为false代表重新可用,然后通过最下面的dfs(x+1,cnt)来进行强制下一行的摆放尝试.

6.为什么要强制进行摆放尝试?因为我写在注释里面了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值