DFS我们称之为深搜,通常解决一些最大最长或者所有可能的问题,一般用递归来实现。因为深搜基本上会遍历每一个结果,但暴力法不同在于,深搜可以通过递归中不满足条件,实现剪枝。
我们先来看一道例题,感受一下深搜。
思路其实比较简单,有点类似于穷举法。我们构建一棵数,每一层依次增加一个没有枚举的数,当到达底层的时候就是一个答案。
比如我们先将第一个数填1,然后由于还有数未填入,继续深入到达下一层。下一层由于第一个数1已经枚举,我们枚举第二个数2。然后继续进入第三层,枚举第三个数3,由于已经把所有的数都枚举完,我们此时要进行一个回溯,回到第二层。由于第二层中只有一个数没有枚举,因此我们已经枚举完第二层的所有可能,因此回溯到第一层。接下来将第二位置填入未被枚举的3,以此反复。
#include<bits/stdc++.h>
using namespace std;
const int N = 10;
//用一个path数组来存储每次到底层的路径
int path[N];
//用一个布尔数组来存储每次已经遍历的点,默认是false
bool st[N];
int n;
//u表示当前的层数
void dfs(int u)
{
//当已经到达最底层了,溯回并输出路径
if( u == n )
{
for(int i = 0 ; i < n ; i++) printf("%d " , path[i] );
//作用跟printf("%s\n",s),默认帮你换行
puts("");
//溯回上一层
return;
}
else
{
//这里从第一个数开始循环
for(int i = 1; i <= n ; i++)
{
//如果该数字未被访问,就使用
if( !st[i] )
{
path[u] = i;
//标记第i个数已经被使用
st[i] = true;
//进入下一层
dfs( u + 1 );
//还原现场
st[i] = false;
}
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
作者:阿柴
链接:https://www.acwing.com/activity/content/code/content/576222/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
深搜总结起来就是:
(1)先想好递归方程
(2)处理好枚举数据,对已遍历的数据要标记
(3)一定一定要还原现场,这是回溯的决定性条件
接下来我们再看一下一道难题:
//y总第一个解法,按列来枚举`
#include<bits/stdc++.h>
using namespace std;
const int N = 20;
char g[N][N];
bool col[N] , dg[N] , udg[N];
int n;
void dfs(int u)
{
if( u == n )
{
for(int i = 0 ; i < n ; i++) puts( g[i] );
puts("");
return;
}
else
{
for(int i = 0 ; i < n ; i++)
{
//当满足列没有皇后,对角线没有皇后,反对角线没有皇后
if( !col[i] && !dg[u + i] && !udg[n - i + u] )
{
//这一格子放置皇后
g[u][i] = 'Q';
//此时这一列,这一对角线,这一反对角线就不能放置皇后了
col[i] = dg[u + i] = udg[n - i + u] = true;
//递归到下一层
dfs(u + 1);
//递归出来后返回上一层,并还原现场
col[i] = dg[u + i] = udg[n - i + u] = false;
//把皇后给做掉
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;
}
//第二种方法,遍历每一个格子
#include<bits/stdc++.h>
using namespace std;
const int N = 20;
char g[N][N];
bool row[N] , col[N] , dg[N] , udg[N];
int n;
//表示第x行第y列,放置了s个皇后
void dfs(int x , int y , int s)
{
//当当前x行已经到达边界,转到下一行,列数归零
if( y == n ) y = 0 , x++;
//当到最后一个行,如果此时已经存在了n个皇后,就输出结果
//为什么不判断y呢?因为最后一行只能放一个皇后
if( x == n )
{
if( s == n )
{
for(int i = 0 ; i < n ; i++) puts( g[i] );
puts("");
}
return;
}
//放皇后
if( !row[x] && !col[y] && !dg[y + x] && !udg[y - x + n] )
{
g[x][y] = 'Q';
row[x] = col[y] = dg[x + y] = udg[y - x + n] = true;
dfs(x , y + 1 , s + 1 );
row[x] = col[y] = dg[x + y] = udg[y - x + n] = false;
g[x][y] = '.';
}
//不放置皇后
dfs( x , y + 1 , s );
}
int main()
{
cin >> n;
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < n; j++) g[i][j] = '.';
}
dfs(0 , 0 , 0);
return 0;
}
作者:阿柴
链接:https://www.acwing.com/activity/content/code/content/580140/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。