前言
重学算法第8天,希望能坚持打卡不间断,每天早起学习算法
明天再来!肝就完了
2月26日,day08 打卡
今日已学完y总的
算法基础课-3.1,3.2
第三章 搜索与图论(一)+ Week4——习题课
共7题,知识点如下
DFS:排列数字、n-皇后问题。
BFS:走迷宫、八数码。
树与图的深度优先遍历:树的重心
树与图的广度优先遍历:图中点的层次
拓扑排序:有向图的拓扑序列
DFS与BFS
DFS
动图
只有无路可走了才会回溯
DFS中最重要的两个概念
回溯、剪枝
AcWing 842. 排列数字
输出全排列
如何用DFS(俗称暴搜)来做
一步一步枚举
结束一条路径后回溯
动图
没必要区分DFS和递归
只要形式是这样的,都可以称为递归
每次存的都是一条路径,递归下一步就没了,不用存一棵树,
而且系统会有一个隐藏的栈来维护路径,不需要开额外空间
回溯的时候一定要注意
每次回来一定要恢复原样,从该点下去的时候是啥样,回来也得是那样
用完的东西一定要放回去
#include <iostream>
using namespace std;
const int N = 10;
int n;
int path[N]; // 用来存走的路
bool st[N]; // 为true表示该数用过了
void dfs(int u) {
if (u == n) {
// 走到n说明这条路已经走完了
for (int i = 0; i < n; i++) printf("%d ", path[i]);
puts(""); // 换行
return;
}
// 还没走到最后一层
for (int i = 1; i <= n; i++) {
if (!st[i]) {
// 如果st[i] == false,即该数i没用过
path[u] = i; // 将i放到当前数上
st[i] = true; // i被用过了
dfs(u + 1); // 走到下一层(进到递归就修改,出来了就要及时恢复)
// 恢复现场
st[i] = false;
}
}
}
int main() {
cin >> n;
dfs(0); // 从第0个位置开始看
return 0;
}
AcWing 843. n-皇后问题
思路1:全排列
与全排列一样搜,每一行只能放一个皇后,枚举每一行,从前往后看皇后应该放到哪个位置
该思路与全排列完全一致,一排一排往下搜,搜完一条路径,折回来继续下一个
剪枝优化
如果走到某一排发现已经不满足性质了,就不往后 走了,直接回溯
将该行删掉,可以看成是将该树枝减掉了
对角线这么看,最上面的是第一条
正着的和反着的
两种对角线对应的截距(就是对角线的编号),
b=y-x
可能为负数,加上n
代码中i是横坐标(x)
u是纵坐标(y)
#include <iostream>
using namespace std;
const int N = 20; // 对角线个数2N-1
int n;
char g[N][N]; // 记录方案
// 每列,正对角线和反对角线,都只能1个
bool col[N], dg[N], udg[N];
// i即x坐标,u即y坐标
void dfs(int u) {
if (u == n) {
for (int i = 0; i < n; i++) puts(g[i]);
puts("");
return;
}
for (int i = 0; i < n; i++) {
if (!col[i] && !dg[u + i] && !udg[n - i + u]) {
// 列,对角线和反对角线都没放过
g[i][u] = 'Q';
col[i] = dg[u + i] = udg[n - i + u] = true; // 已经走过了,置为true
dfs(u + 1);
col[i] = dg[u + i] = udg[n - i + u] = false; // 恢复现场
g[i][u] = '.';
}
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
g[i][j] = '.';
}
}
dfs(0);
return 0;
}
DFS没有经典模板,重要的是顺序
思路二:枚举
枚举,更原始的方式
每个格子都有放与不放2个选择,挨个枚举每个格子
出界了就到下一个格子
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
// col 列 (往左右走) x
// row 行 (往上下走) y
bool col[N], row[N], dg[N], udg[N];
void dfs(int x, int y, int s) {
if (x == n) x = 0, y++; // 第一排找完了,到下一排开头去
if (y == n) {
// 到最后一排了
if (s == n) {
if (s ==