深度优先搜索介绍
D F S DFS DFS,也就是递归,并没有一个固定的模版,而是一种抽象的思想,他的函数体大概长这样:
void dfs(int u){
if(边界条件){
printf("....");
return;
}
for(int i = 0; i < n; ++i){
if(满足条件){
进行赋值操作等;
dfs(u + 1); 进行下一步递归
将之前的赋值操作还原;
}
}
}
经典例题
全排列
板子题:点击此处。
思路
假如是个三位数,我们从第一个位置开始枚举,如果标记数组中这个数未标记,那么把他放入第一个位置并标记,然后递归下一个位置,直到位置满了,那么我们就输出,然后返回,返回后我们需要把标记数组恢复,因为之前的已经输出了,我们需要对这个位置继续递归且数值不能跟之前的一样,所以用循环往前遍历标记数组。
CODE
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10;
int n;
int st[N], p[N];
void dfs(int u){
if(u == n){
for(int i = 0; i < n; ++i) printf("%d ", p[i]);
puts("");
return;
}
for(int i = 1; i <= n; ++i){
if(!st[i]){
p[u] = i;
st[i] = 1;
dfs(u + 1);
st[i] = 0;
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
n皇后
板子题:点击这里。
思路
对行进行递归,由于行数就是皇后数,所以也就是对皇后数进行递归。
先来看返回条件,如果皇后数到达最大值,就输出并返回。
再来看循环条件,一行有 n n n 列,所以要循环 n n n 次,把皇后放在这行的每一格上试一次。
再看判断条件,如果这一列上有皇后不行col[i]
,对角和斜对角上有皇后也不行。这里代码比较难懂,不过我们可以把对角线看做是一个一元一次函数y = x + k
,也就是
y
y
y 是行数,
x
x
x 是列数,而
k
k
k 就是函数的截距。那么这样一来,
行数
u
+
列数
i
=
常数
k
行数u + 列数i = 常数k
行数u+列数i=常数k,而且这个常数
k
k
k 独属于他们这一条斜线,其他斜线的
k
k
k 值与其不同,所以就能保证这一条对角线上没有皇后;同理,对反对角线也是如此。由于反对角线可能会得到负值(截距<0
),则需要加上一个数保证其为正数。
最后记得恢复现场。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
char g[N][N];
int col[N], dg[N * 2], udg[N * 2];
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[u - i + n]){
g[u][i] = 'Q';
col[i] = dg[u + i] = udg[u - i + n] = 1;
dfs(u + 1);
col[i] = dg[u + i] = udg[u - i + n] = 0;
g[u][i] = '.';
}
}
}
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;
}