dfs和bfs都可以对整个空间进行搜索,搜索结构如同一棵树。
但是两者搜索顺序不一样,
dfs是尽可能往深处搜,当搜索到叶子结点就会回溯,之后搜下一个分支,搜到尽头后又进行回溯,循环往复,最终回归起点。
“dfs是个执着的人,不论往哪条分支走,一定会走到尽头,不走到尽头是不会回来的,一旦走到尽头,回去的时候是边回溯边判断是否还有下一条分支能够继续往前走,只有确定当前点所有的路都走不通的时候才会回退一步。”
从使用的数据结构来看,dfs使用的是 栈,从使用的空间来看,dfs往下搜索的时候,我们只需记录某一条路径上的所有点即可,因此它的空间是和搜索树的高度成正比的。
例题:
如何用 dfs 解决全排列问题?
dfs 最重要的是搜索顺序。用什么顺序遍历所有方案。
对于全排列问题,以 n = 3 为例,可以这样进行搜索:
DFS
#include<iostream>
#define cin std::ios::sync_with_stdio(false); cin.tie(0); cin
using namespace std;
const int N = 8;
int path[N];
bool vis[N];
int n;
void dfs(int u)
{
if(u==n)
{
for(int i=0;i<n;++i) cout<<path[i]<<' ';
cout<<endl;
return;
}
for(int i=1;i<=n;++i)
{
if(!vis[i])
{
path[u]=i;
vis[i]=true;
dfs(u+1);
vis[i]=false;
}
}
}
int main()
{
cin>>n;
dfs(0);
return 0;
}
//测试代码感受深搜的过程:
#include<iostream>
using namespace std;
#define debug(a) cout<<#a<<" = "<<a<<endl;
int n;
const int N = 10;
int path[N];
bool st[N];
void dfs(int u)
{
if(u==n)
{
for(int i=0;i<n;i++)
cout<<path[i]<<' ';
cout<<endl;
cout<<endl;
return ;
}
for(int j=1;j<=n;j++)
{
cout<<"j "<<j<<" st["<<j<<"] "<<st[j]<<endl;
if(!st[j])
{
st[j]=true;
debug(j);
path[u]=j;
dfs(u+1);
//把深搜想象成一个鸡思维的人,只有上方递归走到不能走后才会进行下方回溯!
st[j]=false;
cout<<"回溯 ";
debug(j);
cout<<"回溯 ";
cout<<" st["<<j<<"] "<<st[j]<<endl;
}
}
}
int main()
{
cin.tie(0),ios::sync_with_stdio(false);
cin>>n;
dfs(0);
return 0;
}
//感受一下输入5时的输出:
j 1 st[1] 0 //当st[j]为0则将j加入当前搜索路径
j = 1
j 1 st[1] 1
j 2 st[2] 0
j = 2 //因为st[2]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3 //因为st[3]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4 //因为st[4]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5 //因为st[5]=0,因此加入方案
1 2 3 4 5 //每搜索完一个方案接下来则开始回溯
回溯 j = 5
回溯 st[5] 0
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 0 //由于上方j回溯到了4,结束了j=4时的循环,进入到枚举j=5时的循环
j = 5 //st[5]=0,将5纳入当前方案,并进入下一层递归,下面的是在下一层递归中枚举1,2,3,4,5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4 //将4纳入当前方案
1 2 3 5 4 //层数已超,输出方案
回溯 j = 4
回溯 st[4] 0 //回溯到4,下面for进入j=5
j 5 st[5] 1 //st[5]=1,则不可取
回溯 j = 5 //继续回溯
回溯 st[5] 0
回溯 j = 3 //回溯到3,下面for进入j=4
回溯 st[3] 0
j 4 st[4] 0
j = 4 //因为st[4]=0,因此加入方案,下面进入下一层递归,并枚举1,2,3,4,5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3 //因为st[3]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5 //因为st[5]=0,因此加入方案
1 2 4 3 5 //层数已超,输出方案
回溯 j = 5
回溯 st[5] 0
回溯 j = 3
回溯 st[3] 0
j 4 st[4] 1
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
1 2 4 5 3
回溯 j = 3
回溯 st[3] 0
j 4 st[4] 1
j 5 st[5] 1
回溯 j = 5
回溯 st[5] 0
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
1 2 5 3 4
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 1
回溯 j = 3
回溯 st[3] 0
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
1 2 5 4 3
回溯 j = 3
回溯 st[3] 0
j 4 st[4] 1
j 5 st[5] 1
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 1
回溯 j = 5
回溯 st[5] 0
回溯 j = 2
回溯 st[2] 0
j 3 st[3] 0
j = 3
j 1 st[1] 1
j 2 st[2] 0
j = 2
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
1 3 2 4 5
回溯 j = 5
回溯 st[5] 0
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
1 3 2 5 4
回溯 j = 4
回溯 st[4] 0
j 5 st[5] 1
回溯 j = 5
回溯 st[5] 0
回溯 j = 2
回溯 st[2] 0
j 3 st[3] 1
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 0
j = 2
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
1 3 4 2 5
回溯 j = 5
回溯 st[5] 0
回溯 j = 2
回溯 st[2] 0
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 0
j = 2
1 3 4 5 2