关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

【算法入门&图论】【模板】拓扑排序|【模板】单源最短路2 |最小生成树(上)

发布时间:2023-06-28 09:00:17
前言 本专栏收录的均为牛客网的算法题目,内含链表、双指针、递归、动态规划、基本数据结构等算法思想的具体运用。牛客网不仅有大量的经典算法题目,也有大厂的面试真题,面试、找工作完全可以来这里找机会。此外,网站内的编码主题多样化,调试功能可运用性强,可谓是非常注重用户体验。这么好的免费刷题网站还不快入手吗,快去注册开启算法百炼成神之路吧! 1、AB13 【模板】拓扑排序 学会使用邻接表解决图论问题,巧妙利用vector容器 题目链接:拓朴排序 1.1、解题思路 解决拓扑排序之前要先认识什么是拓扑排序: 对一个有向无环图(Directed Acyclic Graph简称DAG)图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。 解决步骤: 使用邻接表将顶点联系起来,辅助数组inDegree表示每个顶点的入度。 借助队列和计数器变量来判断该有向图是否有环: 将入度为零的顶点入队(也就是拓扑图第一个顶点) 取队首,遍历与之相邻的顶点,若该顶点入度减一后为零就将其入队 只要队列非空就循环操作,计算器循环加一,与顶点数比较是否相等 本题末尾也不能输出空格,因此输出拓扑序列时要加限制条件 1.2、代码实现与注释 本题源码: #include #include #include #define M 200001 using namespace std; int main() { int n, m; cin >> n >> m; vector adjList[M]; // 模拟邻接表 int inDegree[M] = { 0 };// 记录每个顶点的入度 int a, b; for (int i = 0; i < m; i++) { cin >> a >> b; adjList[a].push_back(b); inDegree[b]++; } queue que; // 将初始入度为零的顶点入队 for (int i = 1; i <= n; i++) { if (inDegree[i] == 0) que.push(i); } int cnt = 0; // 用来计数,判断改图是否有环 vector res; // 用来输出顶点序列 while (!que.empty()) { int u = que.front(); que.pop(); res.push_back(u); for (int i = 0; i < adjList[u].size(); i++) { // 遍历u的相邻顶点 int v = adjList[u][i]; if (--inDegree[v] == 0) que.push(v); } cnt++; } // 若计数器与顶点数相同则图无环,存在拓扑排序 if (cnt == n) { for (int i = 0; i < res.size(); i++) { cout << res[i]; // 限制输出空格的条件 if (i != res.size() - 1) { cout << " "; } } } else { cout << -1; } return 0; } 重要注释: adjList数组是vector类型的,用来模拟邻接表 使用每个元素为一个数组的vector容器模拟邻接表进行建图 vector[a]所对应的数组中存储着该顶点所指向的其他顶点 inDegree数组代表每一个顶点的入度情况 使用一个队列,初始时将所有入度为0的顶点全部入队,之后采用BFS的思想: 依次取出队头元素并存入结果数组中,然后在邻接表中遍历该队头元素所指向的其他顶点 将这些顶点的入度全部减一,若减一后某顶点的入度变为0,则将该顶点进行入队操作, 重复此步骤直至队列为空为止。 设置一个用于判断图中是否存在环(是否可以得到拓扑序列)的计数器,在弹出队头元素后要将计数器加一,最后队列为空后,若计数器的值与顶点数相同,则说明图不存在环,可以得到拓扑序列。

/template/Home/leiyu/PC/Static