拓扑排序——AcWing 164. 可达性统计

news2024/9/24 23:25:08

目录

拓扑排序

定义

运用情况

注意事项

解题思路

AcWing 164. 可达性统计

题目描述

运行代码

代码思路

改进思路

拓扑排序

定义

拓扑排序(Topological Sort)是对有向无环图(Directed Acyclic Graph,简称DAG)的一种排序方式。在一个有向无环图中,拓扑排序的结果是一个线性的顶点序列,其中对于图中的每一条有向边 (u, v),顶点 u 在序列中都会出现在顶点 v 的前面。如果一个图有多个拓扑排序,那么它不是一个唯一的排序,但所有合法的拓扑排序都符合上述规则。

运用情况

  1. 任务调度:例如,项目管理中的依赖关系,先决条件的课程计划,构建系统中的依赖项解析。
  2. 编译器优化:在编译过程中确定指令的最优执行顺序。
  3. 数据流分析:在程序分析中,为了确定变量的使用和定义顺序。
  4. 资源分配:在资源有限的情况下,确定资源的使用顺序。

注意事项

  1. 图的合法性:图必须是一个有向无环图(DAG)。如果图中含有环,则拓扑排序不可能成功。
  2. 入度的概念:入度是指指向一个顶点的边的数量。拓扑排序的算法通常会从入度为0的顶点开始。
  3. 排序非唯一性:对于同一个DAG,可能存在多个合法的拓扑排序序列。
  4. 算法效率:拓扑排序的时间复杂度通常是 O(V+E),其中 V 是顶点数,E 是边数。

解题思路

  1. 构建图:使用邻接表或邻接矩阵表示图的数据结构。
  2. 计算入度:对于每个顶点,计算其入度(即有多少条边指向它)。
  3. 选择起始点:从入度为0的顶点开始,因为它们没有任何前置条件。
  4. 递归或迭代:将入度为0的顶点加入结果序列,然后将其从图中移除(或标记为已处理),并减少与之相连的其他顶点的入度。重复此过程直到图中没有剩余的顶点或无法找到入度为0的顶点。
  5. 检查结果:如果所有顶点都被处理且结果序列的长度等于顶点总数,则排序成功。如果有顶点未被处理或结果序列长度小于顶点总数,则图中存在环,排序失败。

一个常见的算法实现是使用队列或栈进行迭代处理,每次从队列或栈中取出入度为0的顶点,更新其邻接顶点的入度,并重复这一过程,直到队列或栈为空。

AcWing 164. 可达性统计

题目描述

164. 可达性统计 - AcWing题库

运行代码

#include <iostream>
#include <cstring>
#include <bitset>

using namespace std;

const int N = 30010;

int n, m;
int h[N], e[N], ne[N], idx;
int d[N], q[N];
bitset<N> f[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void topsort()
{
    bool inQueue[N] = {false};  // 标记是否已经入队
    int hh = 0, tt = -1;
    for (int i = 1; i <= n; i++)
    {
        if (!d[i])
        {
            q[++tt] = i;
            inQueue[i] = true;  // 标记入队
        }
    }

    while (hh <= tt)
    {
        int t = q[hh++];
        for (int i = h[t]; ~i; i = ne[i])
        {
            if (--d[e[i]] == 0 &&!inQueue[e[i]])  // 未入队才入队
            {
                q[++tt] = e[i];
                inQueue[e[i]] = true;  // 标记入队
            }
        }
    }
}

int main()
{
    memset(h, -1, sizeof h);
    if (!(cin >> n >> m))  // 输入错误处理
    {
        cerr << "Invalid input. Please enter valid integers." << endl;
        return 1;
    }
    while (m--)
    {
        int a, b;
        if (!(cin >> a >> b))  // 输入错误处理
        {
            cerr << "Invalid input. Please enter valid integers for the edge." << endl;
            return 1;
        }
        add(a, b);
        d[b]++;
    }

    topsort();

    for (int i = n - 1; i >= 0; i--)
    {
        int j = q[i];
        f[j][j] = 1;
        for (int k = h[j]; ~k; k = ne[k])
            f[j] |= f[e[k]];
    }

    for (int i = 1; i <= n; i++)
        cout << f[i].count() << endl;

    return 0;
}

代码思路

  1. 图的表示:使用邻接表存储图的结构,其中 h, e, ne 分别表示头指针数组、边的目标节点和边的下一个节点。

  2. 入度计算d 数组用来存储每个节点的入度(即有多少条边指向该节点)。

  3. 拓扑排序topsort 函数实现了拓扑排序算法,首先将所有入度为0的节点入队,然后循环处理队列中的节点,当处理完一个节点后,将它的所有后继节点的入度减一,如果某个后继节点的入度变为0,则将它入队,直到队列为空。

  4. 可达性统计:在拓扑排序完成后,f 数组是一个位向量数组,用于存储从每个节点出发可以到达的所有节点。从最后一个节点开始向前回溯,对于每个节点 j,初始化 f[j][j] = 1 表示自身可达,然后对于 j 的每一个后继节点 k,将 f[j]f[k] 进行按位或运算,从而合并所有后继节点的可达信息。

  5. 输出结果:最后,遍历 f 数组,输出从每个节点出发可以到达的节点数。

改进思路

  1. 空间优化:使用位向量数组 f 能够有效节省空间,相比于使用整型数组,位向量数组可以更紧凑地存储信息。

  2. 时间优化:拓扑排序的实现是高效的,但是遍历所有的边来更新可达性信息可能会相对耗时。确保数据结构和算法的正确性和效率至关重要。

  3. 输入验证:代码中包含了对输入的验证,确保了程序在遇到非法输入时能够给出错误提示并安全退出。

  4. 避免重复检查:在拓扑排序过程中,inQueue 数组用于避免节点被重复入队,这是必要的,因为它避免了不必要的队列操作。
  5. 简化可达性计算:在回溯阶段,可以尝试避免不必要的按位或运算,但这可能取决于具体的输入数据和图的特性,不一定总是可行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1924264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读笔记】ASPS: Augmented Segment Anything Model for Polyp Segmentation

1.论文介绍 ASPS: Augmented Segment Anything Model for Polyp Segmentation ASPS&#xff1a;用于息肉分割的扩展SAM模型 2024年 arxiv Paper Code 2.摘要 息肉分割在结直肠癌诊断中起着至关重要的作用。最近&#xff0c;Segment Anything Model(SAM)的出现利用其在大规模…

去水印小程序源码修复版-前端后端内置接口+第三方接口

去水印小程序源码&#xff0c;前端后端&#xff0c;内置接口第三方接口&#xff0c; 修复数据库账号密码错误问题&#xff0c;内置接口支持替换第三方接口&#xff0c; 文件挺全的&#xff0c;可以添加流量主代码&#xff0c;搭建需要准备一台服务器&#xff0c;备案域名和http…

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…

交换机和路由器的工作流程

1、交换机工作流程&#xff1a; 将接口中的电流识别为二进制&#xff0c;并转换成数据帧&#xff0c;交换机会记录学习该数据帧的源MAC地址&#xff0c;并将其端口关联起来记录在MAC地址表中。然后查看MAC地址表来查找目标MAC地址&#xff0c;会有一下一些情况&#xff1a; MA…

java.sql.SQLException: Before start of result set

情况描述&#xff0c;在通过JDBC连接数据库时&#xff0c;想直接判断获取的值是否存在&#xff0c;运行时报错。 翻译&#xff1a; 在开始结果集之前 报错截图 解决问题的方法&#xff1a;对结果集ResultSet进行操作之前&#xff0c;一定要先用ResultSet.next()将指针移动至…

4K60无缝一体矩阵 HDMI2.0功能介绍

关于GF-HDMI0808S 4K60无缝一体矩阵的功能介绍&#xff0c;由于直接针对GF-HDMI0808S型号的具体信息较少&#xff0c;我将结合类似4K60无缝HDMI矩阵的一般功能特性和可能的GF-HDMI0808系列产品的特点来进行说明。请注意&#xff0c;以下信息可能不完全针对GF-HDMI0808S型号&…

vienna整流器的矢量分析

Vienna整流器使用六个二极管和六个IGBT&#xff08;或MOSFET&#xff09;组成&#xff0c;提供三个电平&#xff1a;正极电平&#xff08;P&#xff09;、中性点电平&#xff08;O&#xff09;和负极电平&#xff08;N&#xff09;。通过对功率管的控制&#xff0c;Vienna整流器…

xmind梳理测试点,根据这些测试点去写测试用例

基本流&#xff08;冒烟用例必写&#xff09; 备选流 公共测试点&#xff1a;

算法笔记——LCR

一.LCR 152. 验证二叉搜索树的后序遍历序列 题目描述&#xff1a; 给你一个二叉搜索树的后续遍历序列&#xff0c;让你判断该序列是否合法。 解题思路&#xff1a; 根据二叉搜索树的特性&#xff0c;二叉树搜索的每一个结点&#xff0c;大于左子树&#xff0c;小于右子树。…

【企业级监控】Zabbix实现邮箱报警

Zabbix监控自动化 文章目录 Zabbix监控自动化资源列表基础环境前言四、Zabbix邮件告警4.1、实现报警所需的条件4.1.1、告警媒介4.1.2、触发器&#xff08;trigger&#xff09;4.1.3、动作&#xff08;action&#xff09; 4.2、配置告警媒介4.2.1、设置告警媒介参数4.2.2、启用此…

SpringCloud教程 | 第八篇: 使用seata处理分布式事务

1、参考程序员江小北 2、打算降低nacos版本&#xff0c;先学通再看看升级到高版本nacos能不能正常使用。 3、nacos用1.4.1&#xff0c;正常启动单机版的了 4、seata用2.0.0 我看江小北说用的1.4.0的seata&#xff0c;但是图片中的目录文件都找不到&#xff0c;倒是在2.0.0的…

弥合人类与人工智能的知识差距:AlphaZero 中的概念发现和迁移(1)

文章目录 一、摘要二、简介三、相关工作3.1 基于概念的解释3.2 强化学习中生成解释3.3 国际象棋与人工智能 四、什么是概念&#xff1f;五、发掘概念5.1 挖掘概念向量5.1.1 静态概念的概念约束5.1.2 动态概念的概念约束 5.2 过滤概念 一、摘要 人工智能&#xff08;AI&#xff…

计算机网络--tcpdump和iptable设置、内核参数优化策略

tcpdump工具 tcpdump命令&#xff1a; 选项字段&#xff1a; 过滤表达式&#xff1a; 实用命令&#xff1a; TCP三次握手抓包命令&#xff1a; #客户端执行tcpdump 抓取数据包 tcpdump -i etho tcp and host 192.168.12.36 and port 80 -W timeout.pcapnetstat命令 netst…

昇思25天学习打卡营第12天 | ResNet50图像分类

昇思25天学习打卡营第12天 | ResNet50图像分类 文章目录 昇思25天学习打卡营第12天 | ResNet50图像分类ResNet网络模型残差网络结构Building BlockBottleneck 训练数据准备训练数据可视化 网络构建Build Block结构Bottleneck结构ResNet50网络 模型训练与评估训练验证迭代数据集…

Swiftui中几种常用的数据存储方式@AppStorage/UserDefaults/CoreData/File Storage/Keychain等

在 SwiftUI 中&#xff0c;有多种常用的数据存储方式&#xff0c;根据需求的不同&#xff0c;可以选择适合的存储方案。以下是几种常用的数据存储方式&#xff1a; AppStorage/UserDefaults/CoreData/File Storage/Keychain&#xff0c;分别来看一下他们的使用场景和区别。 1.…

【Linux 文件读写描述符重定向 Linux 一切皆文件缓冲区】

文章目录 一、文件的读写操作二、文件描述符三、文件重定向四、理解 Linux 一切皆文件五、文件缓冲区 一、文件的读写操作 文件内容属性 当文件没有被操作的时候&#xff0c;一般文件还是在磁盘当中 文件操作文件内容的操作文件属性的操作&#xff0c;文件操作有可能即改变内容…

实战:docker式部署frp内网穿透-2024.7.13(测试成功)

前提 首先就需要准备好一台云服务器&#xff0c;用于提供公网 IP 和流量转发。至于购买哪家的云服务产品&#xff0c;本着能省则省的原则&#xff0c;这个当然是哪家便宜用哪家呢。 我手上目前有闲置的腾讯云的服务器&#xff0c;刚好可以用来作为内网穿透的机器&#xff0c;…

MySQL篇十:事务

文章目录 前言1. 什么是事务&#xff1f;2. 为什么会出现事务3. 事务的版本支持4. 事务提交方式5. 事务常见操作方式6. 事务隔离级别6.1 如何理解隔离性16.2 如何理解隔离性26.2.1 读-写6.2.2 undo 日志6.2.3 模拟 MVCC6.2.4 RR 与 RC的本质区别 前言 CURD不加控制&#xff0c;…

【探索Linux】P.39(传输层 —— TCP的三次 “握手” 和四次 “挥手” )

阅读导航 引言一、TCP的三次握手1. 简介2. 图解三次握手3. 名词解释&#xff08;1&#xff09;SYN&#xff08;同步序列编号&#xff09;包&#xff08;2&#xff09;SYN-ACK&#xff08;同步确认&#xff09;包&#xff08;3&#xff09;ACK&#xff08;确认&#xff09;包 4.…

【CTF-Crypto】数论基础-02

【CTF-Crypto】数论基础-02 文章目录 【CTF-Crypto】数论基础-021-16 二次剩余1-20 模p下-1的平方根*1-21 Legendre符号*1-22 Jacobi符号*2-1 群*2-2 群的性质2-3 阿贝尔群*2-4 子群2-11 群同态2-18 原根2-21 什么是环2-23 什么是域2-25 子环2-26 理想2-32 多项式环 1-16 二次剩…