dfs讲解+3例题

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进行深度学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值