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

目录

拓扑排序

定义

运用情况

注意事项

解题思路

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. 简化可达性计算:在回溯阶段,可以尝试避免不必要的按位或运算,但这可能取决于具体的输入数据和图的特性,不一定总是可行。

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《基于ArcGIS的可达性分析汇编》是一本介绍利用ArcGIS软件进行可达性分析的文献。可达性分析是研究某一地区内不同位置与基础设施之间的空间关系,帮助决策者评估基础设施的服务范围、辐射范围以及改善交通网络的规划和决策的工具。 这本汇编主要介绍了ArcGIS在可达性分析中的功能和应用。首先,它详细介绍了ArcGIS软件的基本概念和操作方法,包括数据导入、编辑和处理等。 其次,汇编讨论了可达性分析的理论和方法,并介绍了ArcGIS在该领域的应用。通过利用ArcGIS软件的网络分析功能,可以计算不同位置到基础设施的距离和时间。根据这些计算结果,可以进行服务区分析、路径优化以及其他可达性指标的计算。 此外,汇编还介绍了如何使用ArcGIS进行可达性模型的建立和评估。通过构建合适的空间网络模型和设定相应的参数,可以进行不同的可达性分析。同时,借助ArcGIS的可视化功能,可以将结果以地图的形式展示出来,便于对研究区域的交通状况进行直观的了解。 总的来说,《基于ArcGIS的可达性分析汇编》对于想要了解和应用ArcGIS进行可达性分析的研究者和决策者具有很高的参考价值。它不仅介绍了ArcGIS的基本操作方法和网络分析功能,还深入探讨了可达性分析的理论和方法。通过该书的学习,读者可以更好地利用ArcGIS软件进行可达性分析,并在实际决策中提供有用的信息和数据支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱姌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值