图的深度优先搜索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 ...
随机推荐
- OpenCV读一张图片并显示
Java 版本: JavaCV 用OpenCV读一张图片并显示.只需将程序运行时的截图回复.如何安装配置创建项目编写OpenCV代码,可参考何东健课件和源代码或其他资源. package com.gi ...
- unittest实战(一):用例框架
import unittest class forTest0(unittest.TestCase): @classmethod def setUpClass(cls) -> None: prin ...
- Java并发ReentrantLock
ReentrantLock简介 可重入锁,作用是使线程安全.对比于sychronized,它能具有以下特点 减小资源锁的力度 更可控,减少发生死锁的概率 加锁.释放锁都是显示控制的 添加锁的作用时间来 ...
- zookeeper伪集群搭建
zookeeper伪集群搭建 1. 下载zookeeper: https://zookeeper.apache.org/ 2. 解压: tar -zxvf zookeeper-3.4.14.tar.g ...
- 微信SEO怎么做-最新微信SEO干货
星辉信息科技进行微信SEO已经很多年了,结合多年的微信SEO经验通过浅谈微信SEO.微信SEO的3大优势.微信SEO的6个排名技巧.企业和个人微信SEO的4大优化战略来讲,可以完美解决B端C端微信获客 ...
- 初识JVM:(一)JVM工作原理和流程
本文主要参考:http://blog.csdn.net/CSDN_980979768/article/details/47281037?locationNum=7&fps=1 声明:主要用于个 ...
- C++ 指针函数
#include <stdio.h> #include <windows.h> using namespace std; template<typename T> ...
- 如何安装vue-devtool调试工具
1.从git上下载工具压缩包,github下载地址:https://github.com/vuejs/vue-devtools: 2.打开cmd,切换到下载的文件目录下:npm install---- ...
- 用 SendGrid 发送免费电子邮件
1. 概述 SendGrid 免费账号可以限额发送 100/天封邮件,虽然比 Mailgun 的每月 10000 封的免费额度少,但胜成注册无需绑定信息卡. 集成 SendGrid 有 SMTP 和 ...
- nodeJS中定时任务cron的使用
cron模块可以帮助我们在node中定时执行任务.如果你的定时需求是简单的setInterval()与setTimeout()计时器所无法满足的比较复杂的定时规则,推荐使用cron来配置. 安装cro ...