您的位置:首页 > 汽车 > 新车 > 国内免费iphone网站_移动互联网开发技术期末试题_网站seo哪家公司好_网络广告营销策略

国内免费iphone网站_移动互联网开发技术期末试题_网站seo哪家公司好_网络广告营销策略

2025/3/12 23:41:28 来源:https://blog.csdn.net/weixin_73355042/article/details/145907802  浏览:    关键词:国内免费iphone网站_移动互联网开发技术期末试题_网站seo哪家公司好_网络广告营销策略
国内免费iphone网站_移动互联网开发技术期末试题_网站seo哪家公司好_网络广告营销策略

有向图的拓扑排序-BFS求解

题目描述

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环。请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 -1

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x, y)xA 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。


输入格式

  • 第一行包含两个整数 nm
  • 接下来 m 行,每行包含两个整数 xy,表示点 x 和点 y 之间存在一条有向边 (x, y)

输出格式

  • 共一行,如果存在拓扑序列,则输出拓扑序列。
  • 否则输出 -1

数据范围

  • 1 ≤ n, m ≤ 10^5

输入样例

复制

3 3
1 2
2 3
1 3

输出样例

复制

1 2 3

解题思路

解题思路:

我们首先要记录每个结点的入度,即每个结点有几条边指向它,然后找出所有入度为0的结点,将其放入队列,那么从这个结点开始,将它指向其他结点的边删去。如果删去这条边后,原本有这个结点指向的那个结点入度为0(即只有开始这个结点指向它),那么就将其入队。直到遍历到最后一个结点,如果尾指针不等于n,就说明没有经过所有点,那么这条路径就不符合拓扑排序。再重复上述操作,直到所有入度为0的点都枚举完都没找到,那么这个无向图就没有拓扑排序。

  • 一篇很清楚的笔记。

在这里插入图片描述

代码实现

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int h[N], e[N], ne[N];
int q[N], d[N];
int n, m, idx;
void add(int a, int b)
{e[idx] = b;ne[idx] = h[a];h[a] = idx++;
}
bool topsort()
{int hh = 0, tt = 0;for (int i = 1; i <= n; i++){if (d[i] == 0){q[tt++] = i; //找到没有被其他结点指向的元素,将其入队}}while (hh <= tt){int k = q[hh++];for (int i = h[k]; i != -1; i = ne[i]){int j = e[i];d[j]--;   //删去由k指向j的这条边if (d[j] == 0) //如果发现该节点入度为0,即没有其他结点指向他了,就将其入队q[tt++] = j;}}return tt == n; //如果tt=n就表示每个结点都走到了,就是一个拓扑排序
}
int main()
{cin >> n >> m;memset(h, -1, sizeof h);while (m--){int a, b;cin >> a >> b;add(a, b);d[b]++; //入度,即记录b这个结点有几条边指向他}if (topsort()){for (int i = 0; i < n; i++){cout << q[i] << " ";}}elsecout << "-1" << endl;return 0;
}

代码思路总结

该题是一个典型的拓扑排序问题,用于求解有向无环图(DAG)的拓扑序列。拓扑排序的核心思想是通过 BFS(广度优先搜索)DFS(深度优先搜索) 来实现。本题使用的是 BFS 方法,具体实现基于 Kahn 算法


1. 图的表示

  • 使用邻接表存储图:
    • h[N]h[i] 表示节点 i 的第一条边的索引。
    • e[N]e[i] 表示第 i 条边的终点。
    • ne[N]ne[i] 表示第 i 条边的下一条边的索引。
    • idx:用于给每条边分配一个唯一的索引。
  • 使用数组 d[N] 记录每个节点的入度(即有多少条边指向该节点)。

2. 插入边

  • add(int a, int b) 函数用于将一条从节点 a 指向节点 b 的边插入到邻接表中。
  • 使用头插法将新边插入到邻接表中:
    • e[idx] = b:记录边的终点。
    • ne[idx] = h[a]:将新边的下一条边指向 h[a]
    • h[a] = idx++:更新 h[a] 为当前边的索引,并递增 idx

3. 拓扑排序实现

  • 初始化
    • 使用队列 q[N] 存储入度为 0 的节点。
    • 遍历所有节点,将入度为 0 的节点加入队列。
  • BFS 过程
    • 从队列中取出队头节点 k,将其加入拓扑序列。
    • 遍历从 k 出发的所有边,减少邻接节点 j 的入度。
    • 如果邻接节点 j 的入度变为 0,则将其加入队列。
  • 判断是否存在拓扑序列
    • 如果最终队列中的节点数等于 n,则说明图中没有环,拓扑序列存在。
    • 否则,说明图中存在环,无法构造拓扑序列。

4. 主函数

  • 读取输入的节点数 n 和边数 m
  • 初始化邻接表 h-1,表示所有节点的第一条边初始为空。
  • 读取每条边并调用 add 函数插入到邻接表中,同时更新节点的入度。
  • 调用 topsort() 函数判断是否存在拓扑序列:
    • 如果存在,输出拓扑序列。
    • 否则,输出 -1

5. 复杂度分析

  • 时间复杂度:O(n + m),其中 n 是节点数,m 是边数。每个节点和每条边都只会被访问一次。
  • 空间复杂度:O(n + m),用于存储邻接表和队列。

6. 代码细节

  • 入队条件
    • 只有入度为 0 的节点才会被加入队列。
  • 队列的实现
    • 使用数组 q[N] 模拟队列,hh 表示队头,tt 表示队尾。
  • 拓扑序列的存储
    • 队列 q 中存储的节点顺序就是拓扑序列。

7. 示例运行

输入:

复制

3 3
1 2
2 3
1 3
执行过程:
  1. 初始化:
    • 邻接表:
      • h[1] 指向边 (1, 2)(1, 3)
      • h[2] 指向边 (2, 3)
      • h[3] 为空。
    • 入度数组:
      • d[1] = 0d[2] = 1d[3] = 2
  2. 将入度为 0 的节点 1 加入队列。
  3. 处理队列:
    • 取出节点 1,加入拓扑序列。
    • 减少节点 23 的入度:
      • d[2] = 0,将 2 加入队列。
      • d[3] = 1
    • 取出节点 2,加入拓扑序列。
    • 减少节点 3 的入度:
      • d[3] = 0,将 3 加入队列。
    • 取出节点 3,加入拓扑序列。
  4. 最终拓扑序列为 1 2 3
输出:
1 2 3

8. 总结

  • 该代码通过 BFS 实现了拓扑排序,适用于大规模有向无环图。
  • 使用邻接表存储图,适合处理稀疏图。
  • 通过维护入度数组和队列,高效地实现了拓扑排序的核心逻辑。
  • 如果图中存在环,则无法构造拓扑序列,输出 -1

算法刷题记录

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com