深度优先搜索(dfs),宽度优先搜索(bfs),深度优先遍历,宽度优先遍历

2023-10-27

图的遍历:我们希望从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次。

通常有两条遍历图的路径(对有向图和无向图都适用):①深度优先搜索 ;② 广度优先搜索。

一,DFS(深度优先搜索)

深度优先搜索(暴搜):一条路走到黑

1,树(排列数字为例)

由题可知需按照字典序排列,所以共有 种情况。

 如下图所示。

 所谓深搜就是一条路走到黑。以上面的排列数字n=3为例,依次从第一层向下,直到三个位置均满之后,再回溯到上一层,再判断是否下一层还有遗漏情况。也符合字典序要求。

注意,为了避免同一顶点被访问多次,每次每层用过了一个点,需要通过辅助数组(初始值置为“假”或“零”)给该点标记一下(值变为“真”或“一”),说明已经用过。此外也需要对排列路径进行一个记录。但是一次深搜之后还需还原现场(即将标记过的点还原),以便于能继续回溯之后的搜索。

 代码:

#include <iostream>
using namespace std;
const int N=8;
int path[N],st[N];//path数组存路径,st数组表示访问标志数组。
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(!st[i])
    	{
    		st[i]=1;
    		path[u]=i;
    		dfs(u+1);
    		st[i]=0;
		}
	}
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

2,图(n皇后为例):

图的深度遍历:

无向图深搜:

有向图深搜: 

 例题:

剪枝:提前判断当前路径是否合法,不合法提前回溯。

n皇后问题就是满足n*n的数组中,放n个皇后,并且这n个皇后不能同一列,同一行,同一对角线,同一反对角线。所以,基于全排列问题,我们再多加上对角线和反对角线即可。那么对角线和反对角线如何处理呢?

如下图所示:

代码:

#include <iostream>
using namespace std;
const int N=20;
char g[N][N];//存图; 
int col[N],dg[N],udg[N];//col表示列,dg正对角线,udg反对角线; 
int n;
void dfs(int u)
{
	if(u==n)
	{
		for(int i=0;i<n;i++)cout<<g[i]<<endl;
		cout<<endl;
		return ;
	}
	for(int i=0;i<n;i++)
	{
		if(!col[i]&&!dg[u+i]&&!udg[n-u+i])
		{
			col[i]=1,dg[u+i]=1,udg[n-u+i]=1;
			g[u][i]='Q';
			dfs(u+1);
			col[i]=0,dg[u+i]=0,udg[n-u+i]=0;
			g[u][i]='.';
		}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)g[i][j]='.';
	dfs(0);
	return 0;
}

总结:解决回溯问题,实际上就是一个决策树的遍历过程。回溯算法核心就是for循环里面的递归,在递归之前"做选择",递归之后"撤销选择”。回溯算法就是纯暴力枚举,复杂度一般都很高。

二,BFS(广度优先搜索)

bfs核心算法思想:把一些问题抽象成图,从一个点开始,向四周扩散。

一般来说bfs算法都是用“队列”这种数据结构,每次将一个节点周围的所有节点加入队列。

使用队列:与树的层序遍历类似,越是接近根节点越早遍历。

实质:从起点到终点寻找最短路径。

 例题:

1,走迷宫

分析:寻找从左上到右下的最短路径。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
typedef pair<int,int>PII;
const int N=110;
queue<PII>q;//存图上某点坐标; 
int g[N][N];//存图;
int d[N][N];//存路径上的距离;
int m,n;
int bfs()
{
	memset(d,-1,sizeof d);
	q.push({0,0});//第一个点为起点并且标记走过;
	d[0][0]=0;
	while(!q.empty())
	{
		auto t=q.front();
		q.pop();
		
		int dx[4]={0,1,0,-1};
		int dy[4]={1,0,-1,0};
		for(int i=0;i<4;i++)
		{
			int x=t.first+dx[i],y=t.second+dy[i];
			if(x<n&&x>=0&&y<m&&y>=0&&g[x][y]==0&&d[x][y]==-1)
			{
				d[x][y]=d[t.first][t.second]+1;
				q.push({x,y});
			}
		}
	} 
	return d[n-1][m-1];
}
int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			cin>>g[i][j];
		}
	}
	cout<<bfs();
	return 0;
} 

2,八数码问题

 分析:类似于小时候玩的拼图游戏。

首先将输入的一串字符(最开始的状态)存入队列,判断这种状态是否符合题目条件(“12345678x”的状态)即可。

实现该条件存在的问题有:

①状态表示复杂;

处理方案:将3*3的二维数组转化为一维数组;

②记录状态距离困难。

处理方案:将一维数组作为key值,状态改变次数作为value存入哈希表,每改变一次状态,value加一,直到变成状态”12345678x“,如果到达不了最终状态则返回-1;

代码:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <queue>
using namespace std;
int bfs(string s)
{
	queue<string>q;
	unordered_map<string,int>d;
	q.push(s);
	d[s]=0;
	string end="12345678x";
	int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
	while(!q.empty())
	{
		string t=q.front();
		q.pop();
		
		if(t==end)return d[t];
		int distant=d[t];
		int k=t.find('x');
		int x=k/3,y=k%3;
		for(int i=0;i<4;i++)
		{
			int a=x+dx[i],b=y+dy[i];
			if(a>=0&&a<3&&b>=0&&b<3)
			{	
				
				swap(t[k],t[a*3+b]);
				if(!d.count(t))
				{
					d[t]=distant+1;	
					q.push(t);
				}
			    swap(t[k],t[a*3+b]);
			}
			
		}
	}
	return -1;
}
int main()
{
	string s;
	for(int i=0;i<9;i++)
	{
		char a;
		cin>>a;
		s+=a;
	}
	cout<<bfs(s);
	return 0;
}

三,深度优先遍历

例题:树的重心

 题目分析:

 如图为题目样例,最后结果应该是最小值4 。

那么我们应该如何处理这道题呢?

可以利用深搜。我们以删除节点4为例,删除节点4,会生成除了4以外的三个连通子图,分别是以3为根节点的一个子树,以6为根节点的子树以及上面那一块(以1为节点但需要除去以4为根节点的子树)。如图:

我们可以利用深搜算出4下面子树节点数量,至于上面那块,由于深搜是一条路走到黑,不会回头,所以可以利用最大的树节点数量减去已知的子树节点数, 即为上面那块未知节点数量。

代码:

#include <iostream>
#include <algorithm>
#include <cstring> 
#include <cstdio>

using namespace std;
const int M=100010;
const int N=2*M;
int st[M],h[M],e[N],ne[N],idx;
int ans=M,n; 
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)
{
	st[u]=1;//标记u已遍历;
	int res=0;
	int sum=1;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(st[j])continue;
		
		int s=dfs(j);
		res=max(res,s);//求删除u节点时,u节点的下方连通子树中节点的最大值。 
		sum+=s;//包含u节点总子树; 
	}
	res=max(res,n-sum);//上面求得的所有子树中的连通块最大值再跟上方那块比较,求得整棵树的最大连通块最大值。 
	ans=min(ans,res);//寻找删除各个不同节点的情况下最大值中的最小值; 
	return sum;//每次返回子树节点数 
}
int main()
{
	memset(h,-1,sizeof h);
	cin>>n;
	for(int i=0;i<n-1;i++)
	{
	    int a,b;
	    cin>>a>>b;
	    add(a,b);
	    add(b,a);
	}
	dfs(1);
	cout<<ans<<endl;
	return 0;
}

 四,宽度优先遍历

例题:图中点的层次

 题目分析:

n个点m条边的有向图,求出节点1到n的最短距离。

看到最短距离,应该想到bfs,bfs通常是用队列实现。

从1开始遍历即可,最后返回n的距离。

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;
const int N=100010;
int e[N],h[N],ne[N],idx,n,m;
int d[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int bfs()
{
    queue<int>q;
    memset(d,-1,sizeof d);
    d[1]=0;
    q.push(1);
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(d[j]==-1)
            {
                d[j]=d[t]+1;
                q.push(j);
            }
        }
    }
    return d[n];
}

int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    cout<<bfs()<<endl;
    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度优先搜索(dfs),宽度优先搜索(bfs),深度优先遍历,宽度优先遍历 的相关文章

随机推荐

  • npm 安装出错 npm ERR! request to https://registry.npmjs.org/express failed, reason: unable to verify th

    npm 安装 jointjs时 出现 D Project demo gt npm install jointjs npm ERR code UNABLE TO VERIFY LEAF SIGNATURE npm ERR errno UNAB
  • Jetson开发实战记录(一):Jetson家族的基本介绍

    Jetson开发实战记录 一 Jetson家族的基本介绍 一 Jetson家族 二 Jetson家族产品横向对比 1 Jeston Nano 2 Jetson Xavier 3 Jetson Xavier NX 4 Jetson TX2 5
  • 条件编译#if #ifdef #ifndef

    if ifdef和 ifndef区别 1 if if 常量表达式 程序段1 else 程序段2 endif 如果常量表达式的值为真 非0 则对程序段1 进行编译 否则对程序段2进行编译 2 ifdef ifdef 标识符 或 if defi
  • tensorflow自定义网络层、激活函数(self-defined layer)

    highly based on http stackoverflow com questions 39921607 tensorflow how to make a custom activation function with only
  • Python每日一记193>>>AttributeError: 'DataFrame' object has no attribute 'map'

    昨天在运行一段程序的时候 遇到了AttributeError DataFrame object has no attribute map 错误 但是很奇怪 明明之前也是类似的代码 不知道这次为什么出错了 先看一下错误 发现错误发生的代码在以
  • 算法第二章上机报告

    1 实践题目 7 1 二分查找 20 分 输入n值 1 lt n lt 1000 n 个非降序排列的整数以及要查找的数x 使用二分查找算法查找x 输出x所在的下标 0 n 1 及比较次数 若x不存在 输出 1和比较次数 输入格式 输入共三行
  • 调参1——随机森林贝叶斯调参

    贝叶斯调参教程请参考 https blog csdn net weixin 35757704 article details 118480135 安装贝叶斯调参 pip install bayesian optimization 算法简介
  • linux tomcat部署mvc,Spring+SpringMVC+MyBatis项目部署到Tomcat服务器

    其中JDK MySQL以及Tomcat可以直接去官网下载对应版本的安装包 本文采用的版本分别为 安装JDK 拷贝JDK安装包到相应目录下 如 sudo cp jdk 8u231 linux x64 tar gz usr local cd u
  • Qt程序报error: undefined reference to `MainWindow::~MainWindow()'

    编译Qt程序时 编译器报error undefined reference to MainWindow MainWindow 这是因为Qt语法较严格 不会自动生成类的析构函数 需要程序员自己编写 即便里面什么内容也没有 所以 手写好Main
  • Qt 智能指针详细介绍

    1 Qt智能指针概述 Qt 提供了一套基于父子对象的内存管理机制 所以我们很少需要去手动 delete 但程序中不一定所有类都是QObject的子类 这种情况下仍然需要使用一些智能指针 注意 在 Qt 中使用智能指针时 一定要避免发生多次析
  • 数据结构与算法——RB树简介

    二叉树 任何节点最多只允许有两个子节点 二叉搜索树 可以提供对数时间的元素插入和访问 任何节点的键值一定大于其左子树中的每一个节点的键值 并不小于其右子树中的每一个节点的键值 平衡二叉搜索树 平衡的意思是 没有任何一个节点过深 深度过大 二
  • R语言-相关

    相关系数是可以用来描述定量变量之间的关系 相关系数的符号 是表明关系的方向 正相关或负相关 其值 绝对值 大小表示关系的强弱程度 完全不相关时为0 完全相关时为1 一 相关的类型 1 Pearson Spearman和Kendall相关 P
  • nasal脚本起源与环境搭建(flightgear开源项目)

    目录 FlightGear FlightGear下载 nasal 脚本 nasal脚本起源 nasal脚本介绍 使用FlightGear内置的环境 使用开源的Nasal脚本解释器 Create VS project 创建 VS 工程 Fir
  • QT中有关QString的各种数据类型转换

    提示 刚接触QT 对类型转换不太熟悉的朋友们不需要再各个去查了 文章持续将更新有关QT中类型转换的内容 文章目录 一 QString QByteArray QJsonObject std string QStringList UTF 8 一
  • R语言broom包整洁化模型

    文章目录 载入包 建模 broom 整洁模型数据 purrr包向量化函数与broom包结合 broom是tidyverse系列包之一 可以帮助人们获得干净整洁的模型数据结果 有效改善了R语言建模的用户体验 载入包 library tidyv
  • SpringBoot自动装配原理

    文章目录 一 简介 二 自动装配源码分析 三 自动装配以mybatis举例 四 总结 一 简介 Spring Boot 的自动装配 Auto configuration 是 Spring Boot 框架中一项强大的功能 它可以根据应用程序的
  • 2021年中职“网络安全“江西省赛题—B-5:应急响应

    B 5 应急响应 1 黑客通过网络攻入本地服务器 在Web服务器的主页上外挂了一个木马连接 请你找到此连接并删除该连接 将对应的标题名称作为flag值提交 直接去连接去查看网站目录 发现有几个php文件 在3 php中发现了一句话木马 我们
  • word 2013 尾注后继续添加正文的方法

    通常 文档的尾注后面是不能再添加 编辑正文性质的内容的 这篇文章介绍一种稍微 曲折 的方法来解决这一问题 当我们利用尾注的方法在论文中添加参考文献时 如果参考文献后面还有正文内容 那么此方法将对你十分有用 1 准备文档的基本内容 我们先准备
  • ES6 数组内对象去重

    去重Set const arr 张三 张三 三张三 let set new Set arr set 自带去重 Set 张三 三张三 console log set console error Array from set 张三 三张三 去重
  • 深度优先搜索(dfs),宽度优先搜索(bfs),深度优先遍历,宽度优先遍历

    图的遍历 我们希望从图中某一顶点出发访遍图中其余顶点 且使每一个顶点仅被访问一次 通常有两条遍历图的路径 对有向图和无向图都适用 深度优先搜索 广度优先搜索 一 DFS 深度优先搜索 深度优先搜索 暴搜 一条路走到黑 1 树 排列数字为例