首页 > 其他分享 >拓扑排序——AcWing 164. 可达性统计

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

时间:2024-07-14 15:26:41浏览次数:10  
标签:int 拓扑 入度 可达性 164 顶点 排序 节点 AcWing

目录

拓扑排序

定义

运用情况

注意事项

解题思路

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

标签:int,拓扑,入度,可达性,164,顶点,排序,节点,AcWing
From: https://blog.csdn.net/u014114223/article/details/140405949

相关文章

  • 并查集——AcWing 239. 奇偶游戏
    目录并查集定义运用情况注意事项解题思路AcWing239.奇偶游戏题目描述运行代码代码思路改进思路并查集定义并查集(DisjointSetUnion,简称DSU),是一种树形的数据结构,常用于处理一些不交集的合并及查询问题。在并查集中,元素被分成多个不相交的集合,每个集合由一个代表......
  • 最近公共祖先——AcWing 356. 次小生成树
    最近公共祖先定义最近公共祖先(LowestCommonAncestor,LCA)是在一棵有根树中,对于两个节点u和v,LCA是所有公共祖先中深度最大的一个节点。换句话说,LCA是u 和v的共同祖先中距离根节点最远的一个。运用情况最短路径问题:在树中,求两节点间的最短路径,可以先找到它们的LCA,......
  • Floyd算法——AcWing 343. 排序
    目录Floyd算法定义运用情况注意事项解题思路基本步骤AcWing343.排序 题目描述运行代码代码思路改进思路Floyd算法定义Floyd算法,全称Floyd-Warshall算法,是一种用于解决图中所有顶点对之间的最短路径问题的动态规划算法。它适用于带权有向图,且可以处理负权重边(......
  • [CF1646F] Playing Around the Table 的题解
    题目大意有\(n\)种牌,一种\(n\)张,一共\(n\)个玩家,一人\(n\)个。每个人一次将一张牌对给下家,求构造方案使可以在\(n\cdot(n-1)\)次操作之内使第\(i\)个人拥有\(n\)张\(i\)。数据范围满足,\(1\len\le100\)。思路因为直接构造出题目要求的情况会出现如果一个人提......
  • Acwing 5729.闯关游戏 状压DP
    Acwing5729.闯关游戏状压DP题目链接题意:现在进行一个闯关游戏,一共有\(n\)个关卡,第\(i\)个关卡的分数为\(w_i\)。另外还有\(k\)个联动彩蛋。如果玩家通过第\(x\)个关卡后,紧接着通过了第\(y\)个关卡,就可以获得额外\(c\)分。现在你需要恰好通过\(m\)个不同关卡,顺......
  • 最小步数模型——AcWing 1107. 魔板
    最小步数模型定义最小步数模型通常是指在某种约束条件下,寻找从初始状态到目标状态所需的最少操作或移动次数的问题。这类问题广泛存在于算法、图论、动态规划、组合优化等领域。具体来说,它涉及确定一个序列或路径,使得按照特定规则执行一系列步骤后,能够从起始位置或状态转换到......
  • 【AcWing】843. n皇后问题
    剪纸就是判断当前方案一定不合法了就不往下搜了,把这个枝减掉,直接回溯。代码#include<iostream>usingnamespacestd;constintN=10;intn;charg[N][N];//棋盘boolcol[N],dg[N*2],udg[N*2];//分别代表列斜线反斜线有没有占用,对角线个数为2n-1,开2nvoiddfs(......
  • 【AcWing】842. 排列数字(DFS)
    DFS是树形结构,深度优先搜索。dfs可以算作递归。横线上填和前面不一样的数字。每一次向下探索都一条路走到黑,直到不能走再回溯。#include<iostream>usingnamespacestd;constintN=10;intn;intpath[N];//存放走过的路径boolst[N];//存放1~n哪个数用过了,全局b......
  • (nice!!!)LeetCode 3164. 优质数对的总数 II(数组、哈希表)
    3164.优质数对的总数II思路:先找出可以被k整除的nums[i].方法一:统计因子。1、找出数组nums1每个元素的因子,用哈希表来记录每个因子出现的次数。然后再遍历数组nums2进行累加即可。classSolution{public:constintN=1e6+10;longlongnumberOfPairs(vec......
  • [MdOI R5] Many Minimizations & [ARC164F] Many Increasing Problems 题解
    讲下一个思路比较自然的基于自然数幂和的\(O(n\logn)\)且复杂度与\(m\)几乎无关的做法。不难发现让我们计数的问题是保序回归\(L_1\)中一条链的情况。这个情况有一个简单的slope-trick做法:用堆维护斜率,每次push进去两个当前的数,然后pop出一个最大值。最终所有数的和......