-
时间复杂度:
-
最坏情况下为O(V!),其中V是顶点数
-
实际运行时间取决于图的拓扑结构
-
这个实现可以输出有向无环图的所有可能的拓扑排序,并能检测图中是否存在环。
-
算法思想:
-
使用回溯法枚举所有可能的拓扑排序
-
在每一步选择当前入度为0的顶点,递归处理剩余顶点
-
回溯时恢复入度和访问状态
-
-
关键数据结构:
-
inDegree
:记录每个顶点的当前入度 -
visited
:标记顶点是否已被访问 -
currentOrder
:存储当前正在构建的拓扑排序 -
allOrders
:存储所有找到的拓扑排序
-
-
环检测:
如果无法找到任何拓扑排序(
allOrders
为空),说明图中存在环
cpp
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> graph;
vector<int> inDegree;
vector<bool> visited;
vector<int> currentOrder;
vector<vector<int>> allOrders;
void allTopSortUtil(int n) {
// 标志变量,表示是否找到了一个有效的顶点
bool flag = false;
for (int u = 0; u < n; u++) {
// 选择一个入度为0且未被访问的顶点
if (inDegree[u] == 0 && !visited[u]) {
// 减少所有邻接顶点的入度
for (int v : graph[u]) {
inDegree[v]--;
}
// 将当前顶点加入结果并标记为已访问
currentOrder.push_back(u);
visited[u] = true;
// 递归处理剩余顶点
allTopSortUtil(n);
// 回溯:重置访问标记和入度
visited[u] = false;
currentOrder.pop_back();
for (int v : graph[u]) {
inDegree[v]++;
}
flag = true;
}
}
// 如果没有顶点可选,说明已经得到一个完整的拓扑排序
if (!flag) {
if ((int)currentOrder.size() == n) {
allOrders.push_back(currentOrder);
}
}
}
vector<vector<int>> allTopSorts(int n) {
vector<int> inDegree(n, 0);
vector<bool> visited(n, false);
// 计算每个顶点的入度
for (int u = 0; u < n; u++) {
for (int v : graph[u]) {
inDegree[v]++;
}
}
allTopSortUtil(n);
return allOrders;
}
int main() {
// 示例:构建一个有向无环图
int n = 6; // 节点数量
vector<vector<int>> graph(n);
// 添加边
graph[5].push_back(2);
graph[5].push_back(0);
graph[4].push_back(0);
graph[4].push_back(1);
graph[2].push_back(3);
graph[3].push_back(1);
// 获取所有可能的拓扑排序
vector<vector<int>> allOrders = allTopSorts(n);
// 输出结果
if (allOrders.empty()) {
cout << "图中存在环,无法进行拓扑排序!" << endl;
} else {
cout << "所有可能的拓扑排序:" << endl;
for (auto& order : allOrders) {
for (int node : order) {
cout << node << " ";
}
cout << endl;
}
cout << "共找到 " << allOrders.size() << " 种拓扑排序" << endl;
}
return 0;
}