学习笔记-深度优先搜索DFS寻找有向图环路实现

合集下载

深度优先搜索探索中的路径

深度优先搜索探索中的路径

深度优先搜索探索中的路径深度优先搜索(Depth First Search,DFS)是一种用于图和树等数据结构的搜索算法。

在图的深度优先搜索过程中,寻找一条从起始顶点到目标顶点的路径是常见且重要的问题。

本文将探讨深度优先搜索中如何找到路径的方法和实现。

一、路径的定义和表示在深度优先搜索中,路径是指从起始顶点到目标顶点的一条通路。

路径可以用顶点序列或边的序列来表示。

以图为例,设图G=(V,E)表示一个有向图,其中V为顶点集合,E为边集合。

对于路径P={v1,v2,v3,...,vn},其中vi∈V且(vi,vi+1)∈E。

路径中的第一个顶点为起始顶点,最后一个顶点为目标顶点。

二、深度优先搜索中的路径探索1. 基本思想深度优先搜索是一种递归的搜索方式,它以某个顶点为起始点,深度优先地遍历该顶点的邻接顶点,然后递归地遍历邻接顶点的邻接顶点,直到找到目标顶点或遍历完所有路径。

2. 算法步骤(1)判断当前顶点是否为目标顶点。

如果是,则找到了一条路径;(2)如果当前顶点不是目标顶点,继续遍历当前顶点的邻接顶点;(3)对于每个邻接顶点,重复步骤(1)和步骤(2),直到找到目标顶点或遍历完所有路径。

三、路径搜索的实现深度优先搜索中的路径搜索可以通过编程实现。

下面以Python语言为例,给出一个简单的深度优先搜索算法的实现:```pythondef dfs(graph, start, end, path=[]):path = path + [start]if start == end:return [path]if start not in graph:return []paths = []for vertex in graph[start]:if vertex not in path:new_paths = dfs(graph, vertex, end, path)for new_path in new_paths:paths.append(new_path)return paths```在上述代码中,graph为表示图的字典,start为起始顶点,end为目标顶点,path为当前路径。

深度优先搜索和广度优先搜索

深度优先搜索和广度优先搜索

深度优先搜索和⼴度优先搜索 深度优先搜索和⼴度优先搜索都是图的遍历算法。

⼀、深度优先搜索(Depth First Search) 1、介绍 深度优先搜索(DFS),顾名思义,在进⾏遍历或者说搜索的时候,选择⼀个没有被搜过的结点(⼀般选择顶点),按照深度优先,⼀直往该结点的后续路径结点进⾏访问,直到该路径的最后⼀个结点,然后再从未被访问的邻结点进⾏深度优先搜索,重复以上过程,直⾄所有点都被访问,遍历结束。

⼀般步骤:(1)访问顶点v;(2)依次从v的未被访问的邻接点出发,对图进⾏深度优先遍历;直⾄图中和v有路径相通的顶点都被访问;(3)若此时图中尚有顶点未被访问,则从⼀个未被访问的顶点出发,重新进⾏深度优先遍历,直到图中所有顶点均被访问过为⽌。

可以看出,深度优先算法使⽤递归即可实现。

2、⽆向图的深度优先搜索 下⾯以⽆向图为例,进⾏深度优先搜索遍历: 遍历过程: 所以遍历结果是:A→C→B→D→F→G→E。

3、有向图的深度优先搜索 下⾯以有向图为例,进⾏深度优先遍历: 遍历过程: 所以遍历结果为:A→B→C→E→D→F→G。

⼆、⼴度优先搜索(Breadth First Search) 1、介绍 ⼴度优先搜索(BFS)是图的另⼀种遍历⽅式,与DFS相对,是以⼴度优先进⾏搜索。

简⾔之就是先访问图的顶点,然后⼴度优先访问其邻接点,然后再依次进⾏被访问点的邻接点,⼀层⼀层访问,直⾄访问完所有点,遍历结束。

2、⽆向图的⼴度优先搜索 下⾯是⽆向图的⼴度优先搜索过程: 所以遍历结果为:A→C→D→F→B→G→E。

3、有向图的⼴度优先搜索 下⾯是有向图的⼴度优先搜索过程: 所以遍历结果为:A→B→C→E→F→D→G。

三、两者实现⽅式对⽐ 深度优先搜索⽤栈(stack)来实现,整个过程可以想象成⼀个倒⽴的树形:把根节点压⼊栈中。

每次从栈中弹出⼀个元素,搜索所有在它下⼀级的元素,把这些元素压⼊栈中。

并把这个元素记为它下⼀级元素的前驱。

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】深度优先搜索 基本思想:先选择⼀种可能情况向前探索,在探索过程中,⼀点那发现原来的选择是错误的,就退回⼀步重新选择,继续向前探索,(回溯)反复进⾏。

【例题】迷宫问题思路:先随意选择⼀个⽅向,⼀步步向前试探,如果碰到死胡同说明该前进⽅向已经⽆路可⾛,这时⾸先看别的⽅向还是否有路可⾛,若有路可⾛,则该⽅向再次向前试探,若没有,则退回上⼀步,再看其他⽅向是否有路可⾛,,按此原则不断回溯和探索,知道找到⼊⼝为⽌。

框架:int search(int ......){for(i=1;i<=⽅向总数;i++)if(满⾜条件){保存结果;if(到达⽬的地)输出解;else search(k+1);恢复:保存结果之前的状态{回溯⼀步};}}具体代码实现如下:#include<iostream>#include<cstdio>#include<cstring>#define MAXN 20using namespace std;int map[MAXN][MAXN];//表⽰迷宫地图bool temp[MAXN][MAXN];//标记是否⾛过int dx[4]={0,0,1,-1};//横坐标的上下左右int dy[4]={-1,1,0,0};//纵坐标的上下左右int m,n,total,sx,sy,fx,fy,l,r,t;//m,n:地图的长宽,total:⽅案总数,sx,sy起点的横纵坐标,fx,fy:终点的横纵坐标,t:障碍总数,l,r:障碍坐标void search(int x,int y)//x,y:现在所在的点的坐标{if(x==fx&&y==fy)//到达终点{total++;//⽅案总数return; //返回继续寻找}for(int i=0;i<=3;i++)if(temp[x+dx[i]][y+dy[i]]==0&&map[x+dx[i]][y+dy[i]]==1)//判断下⾯要⾛的路是否有障碍if(x+dx[i]>=1&&y+dy[i]>=1&&x+dx[i]<=n&&y+dy[i]<=m)//判断是否超越迷宫边界{temp[x+dx[i]][y+dy[i]]=1;search(x+dx[i],y+dy[i]);temp[x+dx[i]][y+dy[i]]=0;//回溯⼀步}}int main(){cin>>n>>m>>t;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)map[i][j]=1;cin>>sx>>sy;cin>>fx>>fy;for(int i=1;i<=t;i++){cin>>l>>r;map[l][r]=0;}map[sx][sy]=0; search(sx,sy); printf("%d",total); return0;}。

深度优先搜索算法详解及代码实现

深度优先搜索算法详解及代码实现

深度优先搜索算法详解及代码实现深度优先搜索(Depth-First Search,DFS)是一种常见的图遍历算法,用于遍历或搜索图或树的所有节点。

它的核心思想是从起始节点开始,沿着一条路径尽可能深入地访问其他节点,直到无法继续深入为止,然后回退到上一个节点,继续搜索未访问过的节点,直到所有节点都被访问为止。

一、算法原理深度优先搜索算法是通过递归或使用栈(Stack)的数据结构来实现的。

下面是深度优先搜索算法的详细步骤:1. 选择起始节点,并标记该节点为已访问。

2. 从起始节点出发,依次访问与当前节点相邻且未被访问的节点。

3. 若当前节点有未被访问的邻居节点,则选择其中一个节点,将其标记为已访问,并将当前节点入栈。

4. 重复步骤2和3,直到当前节点没有未被访问的邻居节点。

5. 若当前节点没有未被访问的邻居节点,则从栈中弹出一个节点作为当前节点。

6. 重复步骤2至5,直到栈为空。

深度优先搜索算法会不断地深入到图或树的某一分支直到底部,然后再回退到上层节点继续搜索其他分支。

因此,它的搜索路径类似于一条深入的迷宫路径,直到没有其他路径可走后,再原路返回。

二、代码实现以下是使用递归方式实现深度优先搜索算法的代码:```pythondef dfs(graph, start, visited):visited.add(start)print(start, end=" ")for neighbor in graph[start]:if neighbor not in visited:dfs(graph, neighbor, visited)# 示例数据graph = {'A': ['B', 'C'],'B': ['A', 'D', 'E'],'C': ['A', 'F'],'D': ['B'],'E': ['B', 'F'],'F': ['C', 'E']}start_node = 'A'visited = set()dfs(graph, start_node, visited)```上述代码首先定义了一个用于实现深度优先搜索的辅助函数`dfs`。

环路识别 算法

环路识别 算法

环路识别算法
环路识别算法是指通过分析一个给定的网络或图结构,判断其中是否存在环路。

以下是几种常见的环路识别算法:
1. 深度优先搜索(DFS):从一个节点开始进行深度优先搜索,记录访问过的节点并标记为已访问。

如果在搜索路径中遇到已访问的节点,则说明存在环路。

2. 广度优先搜索(BFS):从一个节点开始进行广度优先搜索,使用队列来保存待访问的节点。

在搜索过程中,如果遇到已访问的节点,则说明存在环路。

3. 强连通分量算法:强连通分量是指一个图中的节点集合,其中的任意两个节点都可以相互到达。

通过使用强连通分量算法(如Tarjan算法或Kosaraju算法),可以将图划分为多个强连通分量。

如果存在一个强连通分量的大小大于1,则说明存在环路。

4. 拓扑排序:拓扑排序是一种对有向无环图(DAG)进行排序的算法。

在拓扑排序过程中,将入度为0的节点依次加入排序结果中,并将其邻接节点的入度减1。

如果最终排序结果包含所有的节点,则说明不存在环路;反之,存在环路。

这些算法可以根据具体的需求和应用场景进行选择和优化。

原题目:描述深度优先搜索算法的过程。

原题目:描述深度优先搜索算法的过程。

原题目:描述深度优先搜索算法的过程。

描述深度优先搜索算法的过程深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索图的算法,它是一种递归算法,通过深度的方式探索图的节点以获得解决方案。

步骤使用深度优先搜索算法来遍历图的节点的步骤如下:1. 选择一个起始节点作为当前节点,并将其标记为已访问。

2. 检查当前节点是否是目标节点。

如果是目标节点,则算法结束。

3. 如果当前节点不是目标节点,则遍历当前节点的邻居节点。

4. 对于每个未访问的邻居节点,将其标记为已访问,并将其加入到待访问节点的列表中。

5. 从待访问节点的列表中选择一个节点作为新的当前节点,并重复步骤2-4,直到找到目标节点或所有节点都被访问。

6. 如果所有节点都被访问但没有找到目标节点,则算法结束。

递归实现深度优先搜索算法可以使用递归的方式来实现。

以下是一个递归实现深度优先搜索的示例代码:def dfs(graph, node, visited):visited.add(node)print(node)for neighbor in graph[node]:if neighbor not in visited:dfs(graph, neighbor, visited)在上述代码中,`graph` 是表示图的邻接表,`node` 是当前节点,`visited` 是已访问节点的集合。

算法以起始节点作为参数进行递归调用,并在访问每个节点时打印节点的值。

非递归实现除了递归方式,深度优先搜索算法还可以使用栈来实现非递归版本。

以下是一个非递归实现深度优先搜索的示例代码:def dfs(graph, start_node):visited = set()stack = [start_node]while stack:node = stack.pop()if node not in visited:visited.add(node)print(node)for neighbor in graph[node]:if neighbor not in visited:stack.append(neighbor)在上述代码中,`graph` 是表示图的邻接表,`start_node` 是起始节点。

深度优先搜索算法实现技巧概述

深度优先搜索算法实现技巧概述

深度优先搜索算法实现技巧概述深度优先搜索算法(Depth-First Search,DFS)是一种用于图遍历和搜索的常用算法。

它的基本思想是从初始节点开始,逐个访问与当前节点相邻且尚未访问过的节点,直到无法继续访问为止,然后回溯到上一节点继续搜索,直到遍历完所有节点。

深度优先搜索算法可以用递归或栈实现。

下面将介绍几种常用的深度优先搜索算法实现技巧,帮助读者更好地理解和应用该算法。

1. 递归实现深度优先搜索算法递归是深度优先搜索算法最直观的实现方式之一。

通过递归调用自身来完成节点遍历。

可以按照以下步骤实现:1) 定义一个记录已访问节点的集合visited,初始时为空;2) 从起始节点开始,将其标记为已访问,并输出节点值;3) 遍历该节点的相邻节点,如果相邻节点未被访问过,则递归调用搜索函数访问该节点。

2. 栈实现深度优先搜索算法栈也是深度优先搜索算法的常用实现方式。

通过栈的先进后出特性,实现节点的回溯和遍历。

可以按照以下步骤实现:1) 定义一个记录已访问节点的集合visited,初始时为空;2) 定义一个栈,并将起始节点压入栈中;3) 循环执行以下步骤,直到栈为空:a) 弹出栈顶节点;b) 如果该节点未被访问过,则标记为已访问,并输出节点值;c) 遍历该节点的相邻节点,将未被访问过的相邻节点压入栈中。

3. 剪枝优化深度优先搜索算法在实际应用中,深度优先搜索算法通常会遇到搜索空间非常大的情况,导致算法的效率较低。

为了减小搜索空间,可以引入剪枝优化技巧。

常见的剪枝优化包括:a) 设置深度阈值,当搜索深度超过阈值时,立即返回不再继续搜索;b) 设置节点访问次数限制,每个节点最多被访问固定次数,防止陷入无意义的循环中。

4. 应用场景深度优先搜索算法在许多领域都有广泛应用,下面介绍几个常见的应用场景:a) 图的连通性判断:通过深度优先搜索算法可以判断图中两个节点是否连通;b) 拓扑排序:通过深度优先搜索算法可以对有向无环图进行拓扑排序;c) 迷宫求解:通过深度优先搜索算法可以求解迷宫问题,寻找从起点到终点的路径;d) 词语接龙:通过深度优先搜索算法可以找到两个词语之间的最短变换序列。

DFS讲义(基础)

DFS讲义(基础)

回溯及深度优先搜索内容提要:图的概述、搜索概述、回溯算法、深度优先搜索、搜索的剪枝预备知识1、图的概念1736年瑞士数学家欧拉(Euler)发表了图论的第一篇论文“哥尼斯堡七桥问题”。

在当时的哥尼斯堡城有一条横贯全市的普雷格尔河,河中的两个岛与两岸用七座桥联结起来,见图(1)。

当时那里的居民热衷于一个难题:游人怎样不重复地走遍七桥,最后回到出发点。

为了解决这个问题,欧拉用A,B,C,D 4个字母代替陆地,作为4个顶点,将联结两块陆地的桥用相应的线段表示,如图(2),于是哥尼斯堡七桥问题就变成了图(2)中,是否存在经过每条边一次且仅一次,经过所有的顶点的回路问题了。

欧拉在论文中指出,这样的回路是不存在的。

图可以定义为G=(V,E),其中V是顶点的非空集合,E是边的集合;一般用(Vx,Vy)表示边,其中Vx,Vy∈V。

根据边和顶点的不同特性,图可以分为有向图、无向图、带权图等。

DA图2 无向图BDA图3 有向图V1V32图4 带权图V2图的遍历:即从某个顶点出发,依次访问每个顶点一次。

【例题】两只蚂蚁比赛问题。

两只蚂蚁甲、乙分别处在图G中的顶点a,b处,并设图中各边长度相等。

甲提出同乙比赛:从它们所在顶点出发,走过图中所有边最后到达顶点c处。

如果它们速度相同,问谁最先到达目的地?2、树的概念树形结构是结点之间有分支,并具有层次关系的结构,它非常类似于自然界中的树。

树结构在客观世界中是大量存在的,例如家谱、行政组织机构都可用树形象地表示。

以上表示很像一棵倒画的树。

其中“树根”是张源,树的“分支点”是张明、张亮和张平,该家族的其余成员均是"树叶",而树枝(即图中的线段)则描述了家族成员之间的关系。

显然,以张源为根的树是一个大家庭。

它可以分成张明、张亮和张丽为根的三个小家庭;每个小家庭又都是一个树形结构。

树可以用树形图、嵌套集合、凹入表等方式表示。

其中树形图表示是树结构的主要表示方法:结点用圆圈表示,结点的名字写在圆圈旁边(有时亦可写在圆圈内)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

常用的图的存储结构主要有以下二种:邻接矩阵和邻接表邻接矩阵与邻接表的对比:1、当图中结点数目较小且边较多时,采用邻接矩阵效率更高。

2、当节点数目远大且边的数目远小于相同结点的完全图的边数时,采用邻接表存储结构更有效率。

有向图稀疏邻接矩阵结构深度优先搜索DFS寻找环路Java实现1.import java.util.*;2.import ng.StringUtils;3.public class DFSSparseCycle {4./** 点数 */5.private int vertexCount;6./** 有向图的稀疏邻接矩阵 */7.private int[][] sparseAdjacencyMatrix;8./** 点访问状态, 0未访问 1已访问 */9.private int[] vertexAccessStatus;10./** 追踪栈 */11.private List<Integer> traceStack = new ArrayList<Integer>();12./** 追踪过的点 */13.private List<Integer> tracedVertexs = new ArrayList<Integer>();14./** 环列表 */15.private List<List<Integer>> cycles = newArrayList<List<Integer>>();16.public DFSSparseCycle(int[][] sparseAdjacencyMatrix) {17.this.sparseAdjacencyMatrix = sparseAdjacencyMatrix;18.this.vertexCount = sparseAdjacencyMatrix.length;19.vertexAccessStatus = new int[vertexCount];20.Arrays.fill(vertexAccessStatus, 0);21.}22.public void findCycle() {23.for (int i = 0; i < vertexCount; i++) {24.if (!tracedVertexs.contains(i)) findCycle(i);25.}26.}27.public void findCycle(int vertex) {28.if (vertexAccessStatus[vertex] == 1) {29.int j = 0;30.if ((j = traceStack.indexOf(vertex)) != -1) {31.List<Integer> cycle = newArrayList<Integer>();32.while (j < traceStack.size()) {33.cycle.add(traceStack.get(j));34.j++;35.}36.cycles.add(cycle);37.return;38.}39.return;40.}41.vertexAccessStatus[vertex] = 1;42.traceStack.add(vertex);43.for (int i = 0; i < vertexCount; i++) {44.if (sparseAdjacencyMatrix[vertex][i] == 1) {45.findCycle(i);46.tracedVertexs.add(i);47.}48.}49.traceStack.remove(traceStack.size() - 1);50.}51.public boolean hasCycle() {52.return cycles.size() > 0;53.}54.public List<List<Integer>> getCycles() {55.return this.cycles;56.}57.public static void main(String[] args) {58.// 有向图的稀疏邻接矩阵59.int[][] adjacencyMatrix = { { 0, 1, 1, 0, 0, 0, 0 },60.{ 0, 0, 0, 1, 0, 0, 0 },61.{ 0, 0, 1, 0, 0, 1, 0 },62.{ 0, 0, 0, 0, 1, 0, 0 },63.{ 0, 0, 1, 0, 0, 0, 0 },64.{ 0, 0, 0, 0, 1, 0, 1 },65.{ 1, 0, 1, 1, 0, 0, 1 }66.};67.DFSSparseCycle dfsCycle = newDFSSparseCycle(adjacencyMatrix);68.dfsCycle.findCycle();69.if (!dfsCycle.hasCycle()) {70.System.out.println("No Cycle.");71.} else {72.List<List<Integer>> cycleList =dfsCycle.getCycles();73.for (int i = 0, len = cycleList.size(); i < len; i++) {System.err.println(StringUtils.join(cycleList.get(i), "#"));74.}75.}76.}77.}有向图稠密邻接表结构深度优先搜索DFS寻找环路Java实现1.import ng.StringUtils;2.import java.util.*;3.public class DFSDenseCycle {4./** 有向图的稠密邻接表 */5.private Map<Integer, Set<Integer>> denseAdjacencyMatrix;6./** 点访问状态 */7.private Set<Integer> vertexAccessStatus = newHashSet<Integer>();8./** 追踪栈 */9.private List<Integer> traceStack = new ArrayList<Integer>();10./** 追踪过的点 */11.private List<Integer> tracedVertexs = new ArrayList<Integer>();12./** 环列表 */13.private List<List<Integer>> cycles = newArrayList<List<Integer>>();14.public DFSDenseCycle(Map<Integer, Set<Integer>>denseAdjacencyMatrix) {15.this.denseAdjacencyMatrix = denseAdjacencyMatrix;16.}17.public void findCycle() {18.for (Map.Entry<Integer, Set<Integer>> entry :denseAdjacencyMatrix.entrySet()) {19.int vertex = entry.getKey();20.if (!tracedVertexs.contains(vertex))findCycle(vertex);21.}22.}23.public void findCycle(int vertex) {24.if (vertexAccessStatus.contains(vertex)) {25.int j = 0;26.if ((j = traceStack.indexOf(vertex)) != -1) {27.List<Integer> cycle = newArrayList<Integer>();28.while (j < traceStack.size()) {29.cycle.add(traceStack.get(j));30.j++;31.}32.cycles.add(cycle);33.return;34.}35.return;36.}37.vertexAccessStatus.add(vertex);38.traceStack.add(vertex);39.Set<Integer> vertexs = denseAdjacencyMatrix.get(vertex);40.for (int v : vertexs) {41.if (denseAdjacencyMatrix.containsKey(v)) {42.findCycle(v);43.tracedVertexs.add(v);44.}45.}46.traceStack.remove(traceStack.size() - 1);47.}48.public boolean hasCycle() {49.return cycles.size() > 0;50.}51.public List<List<Integer>> getCycles() {52.return this.cycles;53.}54.public static void main(String[] args) {55.Map<Integer, Set<Integer>> adjacencyMatrix = newHashMap<Integer, Set<Integer>>();56.adjacencyMatrix.put(0, new HashSet(Arrays.asList(1,2)));57.adjacencyMatrix.put(1, new HashSet(Arrays.asList(2,3)));58.adjacencyMatrix.put(2, new HashSet(Arrays.asList(0,3)));59.DFSDenseCycle dfsCycle = newDFSDenseCycle(adjacencyMatrix);60.dfsCycle.findCycle();61.if (!dfsCycle.hasCycle()) {62.System.out.println("No Cycle.");63.} else {64.List<List<Integer>> cycleList =dfsCycle.getCycles();65.for (int i = 0, len = cycleList.size(); i < len;i++) {System.err.println(StringUtils.join(cycleList.get(i), "#"));66.}67.}68.}69.}。

相关文档
最新文档