DFS算法:
上周学习了贪心算法和dp算法,因为经常在leetcode的题解看到dfs算法,在蓝桥杯也有很多dfs相关题目,这周开始学习dfs算法。
思路讲解:
dfs算法就是深度优先搜索,它优先考虑搜索的深度,当搜索到结束条件,也就是结束条件之后就退回一步重新搜索,光看思路太过抽象了,我们可以通过例题来认识dfs算法。
例题:
1.全排列问题:
全排列在学习高中数学排列组合的时候经常会用到,而要实现全排列也很适合用dfs的方法来解决,我们设置将n个不同数字的小球放到不同数字的箱子里。
思路:
- 首先,我们设置dfs的条件,就是当放到最后一个箱子的时候,开始退回一步
- 接着,我们写出主要代码,那就是从最小的小球开始,往右开始放小球
- 最后,写上类似于dfs(n+1)的代码,让小球在取出之后,继续往下进行搜索
代码:
#include<stdio.h>
int a[10],b[10],n;
void put(int box)
{
int i;
if(box == n+1)//put函数的结束标志,返回上一级函数
{
for(i = 1; i <= n; i++)
{
printf("%d",a[i]);
}
printf("\n");
return ;//返回上一级的put函数
}
for(i = 1; i <= n; i++)
{
if(b[i] == 0)
{
a[box] = i;
b[i] = 1;
put(box+1);
b[i] = 0;
}
}
return ;//返回上一级的put函数
}
int main(){
scanf("%d",&n);
put(1);
return 0;
}
运行结果:
2.全排列问题拓展:
题干:
在1到9这9个数中排列出一个三位数相加的等式
思路:
这道题可以通过暴力遍历来解决,但暴力遍历的方法需要用到9重循环,这意味着很高的时间复杂度,所以可以利用dfs算法进行深搜
代码:
#include<stdio.h>
int n[10],record[10],sum;
void add(int box)
{
int i;
if(box == 10)
{
if(n[1]*100+n[2]*10+n[3]+n[4]*100+n[5]*10+n[6]==n[7]*100+n[8]*10+n[9])
{
sum++;
printf("%d%d%d+%d%d%d = %d%d%d\n",n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],n[9]);
}
return ; //返回上一级函数
}
for(i = 1; i <= 9; i++)
{
if(record[i]==0)![在这里插入图片描述](https://img-blog.csdnimg.cn/8e2b263ca8af4ecc810af5ebe6434ccc.png#pic_center)
{
n[box]=i;
record[i]=1;
add(box+1);
record[i]=0;
}
}
return;//返回上一级函数
}
int main()
{
add(1); //函数从1开始
printf("%d",sum/2);
return 0;
}
运行结果:
迷宫问题(最短路径):
题干:
这题的题干大意就是,求(1,1)位置到(p,q)位置的最短路径;
思路:
- 首先,这道题的判断条件为小明找到小红,即tx=m,ty=n
- 接着,由于有四种方向,我们可以定义一个二维数组作为中间值,再对它进行加减来表示横坐标和纵坐标
int next[4][2]={{0,1}, {1,0},{0,-1},{-1,0}};//顺时针,右下左上
for(k=0;k<=3;k++)
{
tx=x+next[k][0];
ty=y+next[k][1];
}
- 在这之后,我们设置二维数组rub[][]来记录是否有障碍,用二维数组record[][]来记录该位置是否被走过
代码:
#include<stdio.h>
int record[51][51],rub[51][51];
int n,m,p,q,min=100000;
int next[4][2]={{0,1}, {1,0},{0,-1},{-1,0}};
void search(int x,int y,int step)
{
int tx,ty,k;
if(x==p&&y==q)//上一个dfs()函数传过来的坐标,做了这个dfs()函数的形参
{
if(step<min)
{
min=step;
}
return ;//返回上一级函数
}
for(k=0;k<=3;k++)
{
tx=x+next[k][0];
ty=y+next[k][1];
if(tx<1 || tx>n || ty<1 || ty>m)//判断是否越界
{
continue;
}
if(rub[tx][ty]==0 && record[tx][ty]==0)
{
record[tx][ty]=1;
search(tx,ty,step+1);
record[tx][ty]=0;
}
}
return ; //返回上一级函数
}
int main(){
int i,j,startx,starty;
scanf("%d %d",&n,&m);//迷宫大小
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&rub[i][j]); //迷宫形状
}
}
scanf("%d%d",&startx,&starty); //小明的坐标
scanf("%d%d",&p,&q); //小红的坐标
record[startx][starty]=1;
search(startx,starty,0);
printf("%d",min);
return 0;
}
运行结果:
注:
dfs常用在图和数的搜索问题上,对于最短路径问题,dfs并不是最优解法,所以我打算在学完树和图之后再回过来对dfs进行深度学习