图的深度优先搜索dfs
图的深度优先搜索:
1.将最初访问的顶点压入栈;
2.只要栈中仍有顶点,就循环进行下述操作:
(1)访问栈顶部的顶点u;
(2)从当前访问的顶点u 移动至顶点v 时,将v 压入栈。如果当前顶点u 不存在未访问的相邻矩阵,则将u 从栈中删除;
主要的几个变量:
| color[n] | 用WHITE、GRAY、BLACK 中的一个来表示顶点i 的访问状态 |
| M[n][n] | 邻接矩阵, 如果存在顶点i 到顶点j 的边,则M[i][j]为true |
| Stack S |
栈, 暂存访问过程中的顶点 |
其中color 数组中, 白色代表“未访问的顶点”, 灰色代表“访问过的顶点”(虽然被访问过了,但仍然可能留有通往未访问顶点的边), 黑色代表”访问结束的顶点”;
有俩种方法实现深度优先遍历
(1)用递归实现的深度优先搜索
#include<stdio.h> #define N 100
#define WHITE 0
#define GRAY 1
#define BLACK 2 int n, M[N][N];
int color[N], d[N], f[N], tt;//color[n]表示该顶点访问与否,d[n]表示该顶点的发现时刻 ,f[n]表示该顶点的结束时刻 ,tt表示时间 //用递归函数实现的深度优先搜索
void dfs_visit(int u) {
int v;
color[u] = GRAY;
d[u] = ++tt;
for(v = ; v < n; v++) {
if(M[u][v] == ) continue;
if(color[v] == WHITE)
dfs_visit(v);
}
color[u] = BLACK;
f[u] = ++tt;//访问结束
} void dfs() {
int u;
//初始化
for(u = ; u < n; u++) color[u] = WHITE;
tt = ; //以未访问的u为起点进行深度优先搜索
for(u = ; u < n; u++) {
if(color[u] == WHITE)
dfs_visit(u);
} //输出
for(u = ; u < n; u++) {
printf("%d %d %d\n", u+, d[u], f[u]);
}
} int main() {
int u, v, k, i, j; scanf("%d", &n);
//初始化
for(i = ; i < n; i++) {
for(j = ; j < n; j++) {
M[i][j] = ;
}
}
//输入数据,构造邻接矩阵
for(i = ; i < n; i++) {
scanf("%d %d", &u, &k);
u--;
for(j = ; j < k; j++) {
scanf("%d", &v);
v--;
M[u][v] = ;
}
} dfs(); return ;
} /*
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0
*/
(2)用栈实现的深度优先搜索
#include<iostream>
#include<stack>
using namespace std; static const int N = ;
static const int WHITE = ;
static const int GRAY = ;
static const int BLACK = ; int n, M[N][N];
int color[N], d[N], f[N], tt;//color[n]表示该顶点访问与否,d[n]表示该顶点的发现时刻 ,f[n]表示该顶点的结束时刻
int nt[N];//记录每个顶点的邻接顶点偏移量,eg:顶点0有俩个顶点1,2;现已经访问过1了,那么, nt[u] = 1; 下次直接访问2 //按编号顺序获取与u相邻的v
int next(int u) {
for(int v = nt[u]; v < n; v++) {
nt[u] = v + ;
if(M[u][v]) return v;
}
return -;
} void dfs_visit(int r) {
for(int i = ; i < n; i++) nt[i] = ; stack <int> S;
S.push(r);
color[r] = GRAY;
d[r] = ++tt; while( !S.empty() ) {
int u = S.top();
int v = next(u);
if(v != -) {
if(color[v] == WHITE) {
color[v] = GRAY;
d[v] = ++tt;
S.push(v);
}
}
else {
S.pop();
color[u] = BLACK;
f[u] = ++tt;
}
}
} void dfs() {
//初始化
for( int i = ; i < n; i++) {
color[i] = WHITE;
nt[i] = ;
}
//设置时间
tt = ; //以未访问的u为起点进行深度优先搜索,设置循环的目的应该是防止该图不是连通图
for(int u = ; u < n; u++) {
if(color[u] == WHITE) dfs_visit(u);
} for(int i = ; i < n; i++) {
cout << i+ << " " << d[i] << " " << f[i] << endl;
}
} int main() {
int u, k, v;
cin >> n; //顶点数 //邻接矩阵置零
for( int i = ; i < n; i++) {
for(int j = ; j < n; j++)
M[i][j] = ;
} //创建邻接矩阵
for(int i = ; i < n; i++) {
cin >> u >> k;//输入顶点和顶点的度
u--;
for(int j = ; j < k; j++) {
cin >> v;
v--;
M[u][v] = ;
}
} dfs(); return ;
} /*
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0
*/
图的深度优先搜索dfs的更多相关文章
- 图的深度优先搜索(DFS)和广度优先搜索(BFS)算法
深度优先(DFS) 深度优先遍历,从初始访问结点出发,我们知道初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接 ...
- 【算法导论】图的深度优先搜索遍历(DFS)
关于图的存储在上一篇文章中已经讲述,在这里不在赘述.下面我们介绍图的深度优先搜索遍历(DFS). 深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj:访问vj之后,又访问vj的一个邻接点, ...
- 图的深度优先搜索算法DFS
1.问题描写叙述与理解 深度优先搜索(Depth First Search.DFS)所遵循的策略.如同其名称所云.是在图中尽可能"更深"地进行搜索. 在深度优先搜索中,对最新发现的 ...
- 深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)
深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历.图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图 ...
- DS图遍历--深度优先搜索
DS图遍历--深度优先搜索 题目描述 给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始 注意:图n个顶点编号从0到n-1 代码框架如下: 输入 第一行输入t,表示有t个测试实例 第二行输入n, ...
- 深度优先搜索DFS和广度优先搜索BFS简单解析
转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...
- 【算法入门】深度优先搜索(DFS)
深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解 ...
- 深度优先搜索 DFS 学习笔记
深度优先搜索 学习笔记 引入 深度优先搜索 DFS 是图论中最基础,最重要的算法之一.DFS 是一种盲目搜寻法,也就是在每个点 \(u\) 上,任选一条边 DFS,直到回溯到 \(u\) 时才选择别的 ...
- 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)
需要说明一点,要成功运行本贴代码,需要重新复制我第一篇随笔<简单的循环队列>代码(版本有更新). 进入今天的主题. 今天这篇文章主要探讨广度优先搜索(BFS)结合队列和深度优先搜索(DFS ...
随机推荐
- .Net Core调用oracle存储过程
一 前言 实战踩坑系列,调用第三方Oracle存储,各种血泪史,现记录如下. 二 入坑 首先,调用Oracle需要安装客户端驱动才行,但是在程序开发中下载客户端驱动是一个不明智的选择.于是,不管是微软 ...
- 前端每日实战:92# 视频演示如何用纯 CSS 创作一颗逼真的土星
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/EpbaQX 可交互视频 此视频是可 ...
- PC端如何下载B站里面的视频?
此随笔只是记录一下: PC端下载B站的视频,在blibli前面加上一个i 然后在视频上鼠标右键,视频另存为+路径即可 PS:网上其他的方法,比如在blibli前面加上kan,后面加上jj等,这些方 ...
- iview必备技能一、表单验证规则
iView表单组件使用async-validator验证器对表单域中数据进行验证,给Form 设置属性 rules,同时给需要验证的 FormItem 设置属性 prop 指向对应字段即可. 完整的验 ...
- vue+webpack工程环境搭建
使用Vue-cli脚手架(属于vue全家桶)快速构建一个项目: [1]首先需要安装好node.js; [2]安装webpack,指令$npm install -g webpack; //如果之前有安装 ...
- 一,kubeadm初始化k8s集群
docker安装 wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo yum inst ...
- Java并发编程(02):线程核心机制,基础概念扩展
本文源码:GitHub·点这里 || GitEE·点这里 一.线程基本机制 1.概念描述 并发编程的特点是:可以将程序划分为多个分离且独立运行的任务,通过线程来驱动这些独立的任务执行,从而提升整体的效 ...
- 3L-最好、最坏、平均、均摊时间复杂度
关注公众号 MageByte,设置星标点「在看」是我们创造好文的动力.后台回复 "加群" 进入技术交流群获更多技术成长. 本文来自 MageByte-青叶编写 上次我们说过 时间复 ...
- Python - 函数形参之必填参数、缺省参数、可变参数、关键字参数的详细使用
Python函数形参 必传参数:平时最常用的,必传确定数量的参数 缺省参数:在调用函数时可以传也可以不传,如果不传将使用默认值 可变参数:可变长度参数 关键字参数:长度可变,但是需要以kv对形式传参 ...
- MVVM相关框架
Caliburn.Micro PropertyChanged.Fody Prism MVVMLight (未完)