拓扑排序+dfs+逆拓扑排序+完全访问节点
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
int n,m;
const int N = 1e5+10; // 定义最大节点数
int h[N], e[N], ne[N], idx; // 邻接表存储图
int st[N]; // 标记数组,0表示未访问,1表示在当前路径上,2表示已完成访问
vector<int> res; // 存储拓扑序列
// 邻接表加边函数
void add(int a, int b) // a->b表示从a到b的有向边
{
e[idx] = b; // 边的终点
ne[idx] = h[a]; // 把新边插入到表头
h[a] = idx++; // 更新表头
}
// DFS函数,返回是否存在环
bool dfs(int u) {
st[u] = 1; // 标记当前节点在访问路径上
// 遍历所有邻接点
for(int i = h[u]; i != -1; i = ne[i]) {
int j = e[i]; // 获取邻接点
if(!st[j]) { // 如果邻接点未访问
if(dfs(j)) return true; // 递归访问,如果发现环则返回true
}
else if(st[j] == 1) { // 如果邻接点在当前访问路径上
return true; // 发现环
}
}
st[u] = 2; // 标记当前节点已完全访问
res.push_back(u); // 将节点加入拓扑序列
return false; // 没有发现环
}
int main()
{
scanf("%d%d", &n, &m); // 输入节点数和边数
memset(h, -1, sizeof h); // 初始化邻接表头为-1
// 输入m条边
for(int i = 0; i < m; i++) {
int a,b;
scanf("%d%d", &a, &b); // 输入一条从a到b的有向边
add(a, b); // 添加这条边
}
bool has_cycle = false; // 标记是否存在环
// 遍历所有节点
for(int i = 1; i <= n; i++) {
if(!st[i]) { // 如果节点i未被访问
if(dfs(i)) { // 从节点i开始DFS
has_cycle = true; // 如果发现环
break;
}
}
}
// 输出结果
if(has_cycle) {
printf("-1"); // 有环输出-1
} else {
// 无环则反向输出拓扑序列
for(int i = res.size()-1; i >= 0; i--) {
printf("%d ", res[i]);
}
}
return 0;
}
此方法比较抽象但是代码简单。看的人多了再补充吧。