判断有向图是否有环

news/2025/2/25 16:19:57

如何判断有向图是否有环

  • 1.dfs,bfs
  • 2.拓扑排序

使用拓扑排序来解决这个问题,首先什么是拓扑排序?一直删除出度为0的顶点直到没有出度为0的顶点,如果最终还有顶点存在就说明有环,并且是由剩下的顶点组成的环。

例如 有有向图的邻接表如下

0->1
1->0
1->2
2->3

首先 3这个顶点出度为 0那先删除跟3有关的邻接表,剩下的邻接表有

0->1
1->0
1->2

然后 2这个顶点出度为0,删除跟2有关的邻接表,剩下的邻接表有

0->1
1->0

已经没有出度为0的邻接表了,剩下的0,1组成了有向图的环

代码实现

// 有向图是否有环
func canFinish(numCourses int, prerequisites [][]int) bool {
   // 邻接表map
    adj := make(map[int]map[int]struct{}, numCourses)
    // 反向邻接表map
    adjR := make(map[int]map[int]struct{}, numCourses)
    for i := 0; i < len(prerequisites); i++ {
        _, ok := adj[prerequisites[i][1]]
        if !ok {
            adj[prerequisites[i][1]] = make(map[int]struct{}, numCourses)

        }
        _, ok = adjR[prerequisites[i][0]]
        if !ok {
            adjR[prerequisites[i][0]] = make(map[int]struct{}, numCourses)
        }
        adj[prerequisites[i][1]][prerequisites[i][0]] = struct{}{}
        adjR[prerequisites[i][0]][prerequisites[i][1]] = struct{}{}

    }
    // 所有顶点集合map
    g := make(map[int]struct{}, numCourses)
    for i := 0; i < numCourses; i++ {
        g[i] = struct{}{}
    }
    return !topology(adj, adjR, g)
}

// 图的拓扑排序  一直删除出度为0的顶点直到所有顶点出度大于0或者没有顶点了
func topology(adj, adjR map[int]map[int]struct{}, g map[int]struct{}) bool {
    var existsZero bool
    for k := range g {
        // 出度为0 删除这个节点
        if _, ok := adj[k]; !ok {
            existsZero = true
            delete(g, k)
            mr, ok1 := adjR[k]
            if ok1 {
                for i := range mr {
                    delete(adj[i], k)
                    if len(adj[i]) == 0 {
                        delete(adj, i)
                    }
                }

                delete(adjR, k)
            }
        }

    }

    if len(g) > 0 && existsZero {
        return topology(adj, adjR, g)
    }

    if len(g) > 0 && !existsZero {
        return true
    }

    return false
}

转载于:https://www.cnblogs.com/fwdqxl/p/10087372.html


http://www.niftyadmin.cn/n/4556650.html

相关文章

C语言中的小数如果用int形式输出

如果想进行四舍五入 而是直接读取该浮点数所在内存 并没有对浮点数进行强制转换 在调用printf时 1.6); return 0;}会得到如下运行结果&#xff1a;-17179869180x9999999APress any key to continue由此可见 ||| 如果执行如下程序&#xff1a;int main(int argc 得到的结果应该是…

Spring AOP创建代理对象源码解析

引言 概述&#xff1a; AOP系列文章&#xff1a; 【1】Spring Aop初始化源码分析 【2】Spring AOP创建代理对象源码解析 【3】Spring AOP 链式调用过程源码解析 【4】Spring 事务执行过程源码解析 1 工程简介 1.1 pom <properties><project.build.sourceEncoding>…

1.处理当前时间前后的日期范围 2.处理日期格式

Month(month) {//处理当前时间前后的日期范围 var time new Date(); time.setDate(time.getDate());//获取Day天后的日期 var y time.getFullYear(); var m; if (time.getMonth() month 1>12){ y y1; m time.getMonth() month - 11;//获…

Spring AOP 链式调用过程源码解析

引言 概述&#xff1a; AOP系列文章&#xff1a; 【1】Spring Aop初始化源码分析 【2】Spring AOP创建代理对象源码解析 【3】Spring AOP 链式调用过程源码解析 【4】Spring 事务执行过程源码解析 1 工程概述 1.1 pom <properties><project.build.sourceEncoding>…

sql多表多字段显示

ADDRESS&#xff09; SELECT [A.ID] Name&#xff09; B表&#xff08;ID&#xff08;和A表建立关系&#xff09; B 表 WHERE [A.ID][B.ID] 这个简单的你看懂了 你在自己试着做上面的 我只告诉你个原理 要学会自己的动手能力 还有就是做个视图 也可以的 ||| select a.id 上面的…

P4148 简单题(KDTree)

传送门 KDTree 修改权值当做插入节点&#xff0c;不平衡就暴力重构&#xff0c;询问的时候判断当前节点代表的矩形是否在询问的矩形的&#xff0c;是的话返回答案&#xff0c;相离返回0&#xff0c;否则的话判断当前点是否在矩形内&#xff0c;然后继续递归下去 //minamoto #in…

怎样学习单片机的C语言

应该有您要的资料 http://www.ddic.cn/您到这个网站看看

day 14 - 2 生成器练习

相关练习 1、处理文件&#xff0c;用户指定要查找的文件和内容&#xff0c;将文件中包含要查找内容的每一行都输出到屏幕 #比较 low 的方法 def check_file(filename,aim):with open(filename,encodingutf-8) as f: #句柄 : handler,文件操作符&#xff0c;文件句柄for line in…