我正在研究不同的算法,包括 - 关于拓扑排序有一个美丽的问题:
给定一个有向图,即一组由箭头连接的顶点。是否可以对顶点进行编号,使任何箭头从数字较小的数字指向数字较大的数字?
例子:
很明显,这必须是一个没有循环的图。
而且我很容易在谷歌上搜索到这种拓扑排序搜索算法被称为“Tarjan 算法”
然后魔法开始了。
在很多 地方,Tarjan 的算法,甚至它解决的问题,表述方式都大相径庭:“Tarjan's algorithm for offline LCA (least common nucleus, LCA) search”
我知道,显然,从问题的一种表述到另一种表述之间存在某种美妙的过渡,但我找不到它是一种什么样的过渡?Tarjan 算法是否有专门针对拓扑排序的解释?
在评论中,有人告诉我,Tarjan 可能有两种完全不同的“名义”算法,它们在含义上并不相关。是这样吗?
添加:
我找到了一篇相对容易理解的文章(Stanislav Volodarsky 在评论中向我指出)
然后我用 VSC 重写了这个程序,链接在文章的底部。
同时,我取了“算法操作示例”文章中给出的图形,将顶点名称中的字母替换为1到5的数字。我在那里输入了8条边。
该程序的工作结果是矛盾的:它发出了0 1 3 5 4 2. 现在,注意,问题是:它是什么?
程序:
#include <iostream>
#include <vector>
#include <conio.h>
using namespace std;
int n=5; // число вершин
vector<int> g[8]; // граф
bool used[8];
vector<int> ans;
void dfs (int v) {
used[v] = true;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (!used[to])
dfs (to);
}
ans.push_back (v);
}
void topological_sort() {
for (int i=0; i<n; ++i)
used[i] = false;
ans.clear();
for (int i=0; i<n; ++i)
if (!used[i])
dfs (i);
reverse (ans.begin(), ans.end());
}
int main(){
g[0] = {1, 2};
g[1] = {1, 3};
g[2] = {1, 4};
g[3] = {1, 5};
g[4] = {2, 4};
g[5] = {3, 4};
g[6] = {3, 5};
g[7] = {4, 5};
topological_sort();
for( size_t i=0; i<ans.size(); ++i )
cout << ans[i] << " ";
getch();
}
结果图片:


您通过填写做错了
g-这不是边列表,而是邻接列表,即g[i]包含一个向量,该向量具有从第 i 个顶点开始的弧的顶点数。两次更改[8]为[5]和结果: