首页 > 其他分享 >深度优先搜索 DFS

深度优先搜索 DFS

时间:2024-07-08 16:12:40浏览次数:16  
标签:字符 优先 return 递归 int DFS 枚举 搜索 sf

<目录

深度优先搜索 \(\sf\small\color{gray}Depth\ First\ Search\)

基本思想

基于递归的 执着 的枚举算法
\(\hspace{2cm}\)——\(\sf\small\color{black}David\)

这句话里有三个关键词。
\(\boxed{\sf递归}\boxed{\sf\textit{执着}}\boxed{\sf枚举}\)

枚举

枚举,可谓是解决问题的基本思路了。
在一个范围内,所有的情况我都给你算一边,不就完啦?
可是如果人算,那就太浪费劳动力了。
所以,计算机的超强计算能力便派上用场了。

递归

如何基于递归呢?
每一次枚举,他都有一个状态。
如果这个状态是多维的,
不基于递归,就是一堆 for
基于递归,就是一个清清爽爽的函数了。
每一次执行函数,都处理一维的状态,
多递归几层,就把繁琐的多维状态处理掉了。

执着

为什么说它是执着的呢?
只要没有枚举完,
或者没有达到目标态,
它就停不下来。
这就是 执着

遍历树

DFS的遍历树大概长这样:
DFS Tree

分类

按照我的理解,将其分为两类。

穷举

穷举,就是把所有的情况都算一遍,通过每一次的结果,得出最后的结果。

字符全排列

输入一行字符串(符合字典序),长度不超过10位,请按字典序输出所有的排列情况以及总的排列种数。保证有所字符不会重复。

全排列,就是和原串相同有着相同的元素,可是又不同于原串的有序串。
字符串的每一位都和另一位可以组成一种不同的情况,所以一位就是一维。
注意的是,当你枚举完了某一位上的字符,再换字符的的时候,你会很容易的想到,应该把原来的字符给换掉。
暂停! 这一点很重要。你换掉字符的过程,被称之为 \(\sf\color{red}回溯\) 。
回溯是进入的反义词。当进入完成时,你就需要回来,也就是回溯。
依照递归函数三要素,我们来分析:

调用自身

需要使用 for 循环枚举所有字符,如果此字符还没被用,就进入下一层枚举。

for(int i=0;i<len;i++)
{
	...
	odd(...);
	...
}
状态转移

需要转移的肯定是层数以及用过的字符。

for(int i=0;i<len;i++)
{
	if(have[i])	continue;
	ans[t]=in[i],have[i]=true;
	odd(t+1);
	ans[t]=0,have[i]=false;
}
递归边界

什么时候撞南墙呢?显然,如果我已经枚举完了,那么枚举就结束了。

if(t==len)
{
	sum++;
	for(int i=0;i<len;i++)
		printf("%c ",ans[i]);
	printf("\n");
	return;
}
完整代码
#include<cstdio>
#include<cstring>
char ans[11],in[11];
bool have[11];
int len,sum;
void odd(int t)
{
	if(t==len)
	{
		sum++;
		for(int i=0;i<len;i++)
			printf("%c ",ans[i]);
		printf("\n");
		return;
	}
	for(int i=0;i<len;i++)
	{
		if(have[i])	continue;
		ans[t]=in[i],have[i]=true;
		odd(t+1);
		ans[t]=0,have[i]=false;
	}
}
int main()
{
	scanf("%s",&in);
	len=strlen(in);
	odd(0);
	printf("%d",sum);
	return 0;
}

复杂状态转移

有些时候,状态不只是光 +1 就好,可能是向上走,可能是转个圈……

走迷宫

给一张地图, N 表示变长, . 表示空地, # 表示墙壁,请问是 YESNO 可以从一个点 (x1,y1) 走到另一个点 (x2,y2)

这一道题的状态明显比穷举的要复杂,有 xy 两个维度的状态了。
只是转移方式和目标态不一样,其他的都差不多。

调用自身+状态转移

放在一起写吧。

坐标控制

为了好写,装进数组。

const int D[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
出图

出图就不好玩了。

bool outmap(int x,int y)
	{return (x<0||x>=n||y<0||y>=n);}
转移+回溯

Map[x][y] 标记是否走过,防止转圈。

for(int i=0;i<4;i++)
{
	const int Nx=x+D[i][0];
	const int Ny=y+D[i][1];
	if(outmap(Nx,Ny))
		continue;
	if(map[Nx][Ny])
		continue;
	map[x][y]=true;
	maze(Nx,Ny);
	map[x][y]=false;
}
目标态

目标态是终点,所以终点是南墙。

if(finish)	return;
if(x==hb&&y==lb)
{
	printf("YES\n");
	finish=true;
	return;
}
完整代码
#include<cstdio>
#include<iostream>
#include<cstring>
bool map[105][105],finish=false;
int n,ha,la,hb,lb;
const int D[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
void scanmap()
{
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
		{
			char o;
			std::cin>>o;
			if(o=='.')
				map[i][j]=false;
			else if(o=='#')
				map[i][j]=true;
		}
	return;
}
bool outmap(int x,int y)
{
	return (x<0||x>=n||y<0||y>=n);
}
void maze(int x,int y)
{
	if(finish)
		return;
	if(x==hb&&y==lb)
	{
		printf("YES\n");
		finish=true;
		return;
	}
	for(int i=0;i<4;i++)
	{
		const int Nx=x+D[i][0];
		const int Ny=y+D[i][1];
		if(outmap(Nx,Ny))
			continue;
		if(map[Nx][Ny])
			continue;
		map[x][y]=true;
		maze(Nx,Ny);
		map[x][y]=false;
	}
	return;
}
int main()
{
	int k;
	scanf("%d",&k);
	for(int i=0;i<k;i++)
	{
		memset(map,false,sizeof map);
		finish=false;
		scanf("%d",&n);
		scanmap();
		scanf("%d%d%d%d",&ha,&la,&hb,&lb);
		if(map[ha][la]==true||map[hb][lb]==true)
		{
			printf("NO\n");
			continue;
		}
		map[ha][la]=true;
		maze(ha,la);
		if(!finish)
			printf("NO\n");
	}
	return 0;
}

算法优劣

照例,我们来谈谈算法优劣。
DFS 编程难度非常小,是顺推的。
可是它有着递归函数所给的累赘……
复杂度过不去啊。


完结散花_

标签:字符,优先,return,递归,int,DFS,枚举,搜索,sf
From: https://www.cnblogs.com/PCwqyy/p/18290083/DepthFirstSearch

相关文章

  • 广度优先搜素 BFS
    广度优先搜索\(\sf\small\color{gray}Breadth\First\Search\)基本思想广度优先搜索,个人认为,和深度优先搜索对比理解要好得多。广度优先搜索,亦称层次遍历,指的是在遍历树上按照从上至下,从左至右的次序遍历整棵树。让我们来看看BFS和DFS的遍历树吧。BFSDFS......
  • 【DFS(深度优先搜索)详解】看这一篇就够啦
    【DFS详解】看这一篇就够啦......
  • 0算法基础——深度优先搜索(c++)
            搜索是对一个事物的查询。他可以给出两点最短路,还能求方案数等等。好的,正文开始:深度优先搜索    深度优先搜索(dfs)顾名思义就是从深度的角度出发进行搜索。具体来讲,就是完成一个步骤后将它的每一个子步骤都试一遍,注意是先搜完子步骤(一般认为子步骤层......
  • 给你的博客加上搜索功能!
    15.搜索功能搜索功能是非常重要的,但VuePress内置的搜索功能,只是基于headers的搜索——它会自动为所有页面的标题、h2​和h3​构建起一个简单的搜索索引,也就是我们能搜索的东西只有标题,如果标题里没有你输入的关键字,就搜不到。也就是说,不能搜索Markdown文件里的内容,非......
  • 【DFS】深度优先搜索 洛谷选数例题讲解
    DFS深搜选数问题看一看题......
  • HDFS分布式集群搭建
    1、集群简介Hadoop集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起。另外,对于Hadoop的集群来讲,可以分为两大类角色:master和slave。(1)HDFS集群:负责海量数据的存储,集群中的角色主要有:NameNode(一个,master)、DataNode(若干,slave)和SecondaryName......
  • everything高级搜索-cnblog
    everything高级搜索用法基础4选项验证总结搜索方式高级搜索搜指定路径文件名: 文件名路径不含文件名: !文件名包含单词路径包含指定内容: 路径content:内容大小写区分大小写搜索搜指定路径文件名: case:文件名路径全字匹配全字搜指定路径文件名: whol......
  • 回溯大合集+主元素+DFS图
    子集和问题importjava.util.Scanner;​publicclassMain{  staticintn;//元素个数  staticinttarsum;//目标和  staticintremainSum=0;//当前元素加到最后一个元素的总和,剩余元素和  staticintsesum=0;//已选元素之和  static......
  • STL学习——栈,队列,set,优先队列
    栈:stack容器内元素的访问​由于栈(stack)本身就是一种后进先出的数据结构。在STL中stack中只能通过top()来访问栈顶元素栈上的基本操作栈的基本操作包括:函数名用途push(x)将x入栈top()获得栈顶元素pop()用以弹出栈顶元素empty()可以检测stack内是否为空,返回true为空,返回fa......
  • 力扣第22题:括号生成 深度优先搜索(DFS)和它的优化(C++)
    数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。示例:输入:n=3输出:["((()))","(()())","(())()","()(())","()()()"]思路递出去,再归回来,是为递归。DFS算法是利用递归思想的一种搜索算法。想象一个矿井,从地面到井底有多层......