拓扑排序
给定一张有向无环图,将所有顶点排序,排序后的序列
如下图的一个拓扑序列是:
拓扑序列不唯一!

Kahn 算法
设
Kahn 的算法核心是用队列维护一个入度为
算法步骤:
- 初始时,队列
压入所有入度为 的顶点。 - 每次从
弹出一个顶点 ,将 加入 ,并将 的所有邻点的入度减 ,即删除 的所有出边。 - 若
的邻点 的入度变为 ,则将 压入 。 - 重复步骤 2 到 3,直到
为空。
Kahn 算法的时间复杂度是
cpp
vector<int> e[MAXN], t;
int din[MAXN];
void Kahn() {
queue<int> q;
for (int i = 1; i <= n; i++) {
if (!din[i]) {
q.push(i);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
t.push_back(u);
for (int v : e[u]) {
din[v]--;
if (!din[v]) {
q.push(v);
}
}
}
if (t.size() == n) {
for (int i = 0; i < n; i++) {
cout << t[i] << " ";
}
} else {
cout << "图中存在环" << endl;
}
}DFS 算法
设
DFS 的算法核心是变色,搜索的过程中给节点进行染色,如果存在拓扑序列,则每个节点的颜色都会经历
算法步骤:
- 初始时每个节点都为
,即未访问。 - 枚举每个节点
,执行 DFS,进入节点 时,将 的颜色置为 ,然后枚举 的邻点 ,如果 的颜色为 ,说明 尚未访问,则递归进入 。 - 如果枚举完
的所有邻点后,没有发现环,则 的颜色置为 ,并将 加入 。 - 如果发现
的某一邻点 的颜色为 ,说明回到了祖先节点,则说明存在环,则停止搜索,一路返回 false,退出程序。
DFS 算法的时间复杂度是
cpp
vector<int> e[MAXN], t;
int c[MAXN];
bool DFS(int u) {
c[u] = -1;
for (int v : e[u]) {
if (c[v] == -1) return false;
else if (c[v] == 0) {
if (!DFS(v)) return false;
}
}
c[u] = 1;
t.push_back(u);
return true;
}
void topoSort() {
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++) {
if (c[i] == 0) {
if (!DFS(i)) {
cout << "图中存在环" << endl;
return;
}
}
}
reverse(t.begin(), t.end());
for (int i = 0; i < n; i++) {
cout << t[i] << " ";
}
}思考:如何求字典序最大/最小的拓扑序列?
