深度优先搜索就是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成。
下图为一棵树的深度优先遍历(蓝色数字表示遍历顺序):
![](https://i-blog.csdnimg.cn/blog_migrate/7520f55414c7fca9a693c7cb2eb9c87f.png)
DFS常用于解决有多少种情况、多少条路径、最大路径等。
核心算法:
void dfs(int dee){//dee是深度
if(dee>n){//递归边界
print();return;//如果达到n,那么输出
}
for(int i=1;i<=n;i++){//for轮流固定数字
if(!gd[i]){//判断数字是否用过
gd[i]=1;//若没用过,将其标记为用过
a[dee]=i;//将这个数字固定下来
dfs(dee+1);//递归深搜
gd[i]=0;//深搜完毕,将其取出,开始下一轮
}
}
return;
}
例题1:洛谷P1706 全排列问题
题目描述:
![](https://i-blog.csdnimg.cn/blog_migrate/dcd8fdf842aa295570ffa19e4051761e.png)
这是一道很标准的深搜题,求n个数的排列情况有多少种并把它们全输出。
解题代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;//输入的数
int a[15],b[15];//第一个用来标记数有没有选过,第二个标记输出数的顺序
void sc(){//输出函数
for(int i=1;i<=n;i++)
printf("%5d",b[i]);//注意题目要求“每个数字保留5个常宽”
cout<<endl;//换行
}
void dfs(int l){
if(l>n){//判断停止条件
sc();//调用函数
return;//返回
}
for(int i=1;i<=n;i++){//循环
if(!a[i]){//如果数没有被选过
a[i]=l;//数被选过了
b[l]=i;//数是第几个被选的,也就是输出顺序
dfs(l+1);//回溯
b[l]=0;
a[i]=0;
}
}
}
int main(){
cin>>n;//输入
dfs(1);//调用函数
return 0;
}
例题2:洛谷 P 1065 迷宫
题目描述:
![](https://i-blog.csdnimg.cn/blog_migrate/014b135b88848ac6ffe9681d77e47447.png)
迷宫问题也是很典型的深搜题目,因为要枚举走的步数,以及走错路时退回来换下一条路。
解题代码如下:
#include<bits/stdc++.h>
using namespace std;
bool G[15][15],VIS[15][15];//G为总地图,VIS记录是否访问
int n,m,d[5]={-1,0,1,0,-1};//方向不解释
int nx,ny,ex,ey,CNT;
//nx,ny起点坐标;ex,ey终点坐标,CNT路径条数
void dfs(int x,int y)
{
if (x ==ex&&y ==ey)//如果到终点
{
CNT++;//路径加一
return;//回去继续查找
}
for (int k=0;k<4;k++)
{
int l=x+d[k];int r=y+d[k+1];
if (l>=1&&r>=1&&l<=n&&r<=m&&!G [l][r]&&!VIS [l][r])
{
VIS [l][r]=true;//标记为已访问
dfs (l,r);
VIS [l][r]=false;//回溯
}
}
return;
}
int main ()
{
int t,zx,zy;
cin>>n>>m>>t>>nx>>ny>>ex>>ey;
G[nx][ny]=true; //这就是许多人(我)40分的原因
//因为dfs函数里并没有将起点设为已访问
//所以在后面的访问里,可能访问起点许多次
//所以你的答案可能比标准答案多
while(t--)
{
cin>>zx>>zy;
G[zx][zy]=true;//设为障碍
}
dfs (nx,ny);//从起点开始寻找
cout<<CNT;
return 0;
}