前向星存图之环的判断与记录
基本思路是:
- 使用 DFS 遍历图
- 记录每个节点的访问状态(未访问、访问中、已访问)
- 当访问到一个已处于 "访问中" 状态的节点时,说明发现了环
- 通过回溯路径构建完整的环>
完整代码:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXM = 2e5 + 5; // 无向图边数是有向图的2倍
// 链式前向星结构
struct Edge {
int to, next;
} edge[MAXM];
int head[MAXN], edgeCnt;
// 环检测相关变量
int vis[MAXN]; // 0:未访问, 1:访问中, 2:已访问
int parent[MAXN]; // 记录父节点
vector<int> cycle; // 存储找到的环
// 添加无向边
void addEdge(int u, int v) {
edge[edgeCnt].to = v;
edge[edgeCnt].next = head[u];
head[u] = edgeCnt++;
edge[edgeCnt].to = u;
edge[edgeCnt].next = head[v];
head[v] = edgeCnt++;
}
// 查找环的DFS函数
bool findCycle(int u, int pre) {
vis[u] = 1; // 标记为访问中
parent[u] = pre;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
// 跳过父节点(无向图中需要避免重复访问父节点)
if (v == pre) continue;
if (vis[v] == 0) { // 未访问节点,继续DFS
if (findCycle(v, u)) return true;
} else if (vis[v] == 1) { // 发现环
// 回溯构建环
cycle.push_back(v); // 环的起点
int cur = u;
while (cur != v) {
cycle.push_back(cur);
cur = parent[cur];
}
return true;
}
}
vis[u] = 2; // 标记为已访问
return false;
}
// 重置环检测状态
void resetCycleDetection() {
memset(vis, 0, sizeof(vis));
cycle.clear();
}
int main() {
int n, m;
cin >> n >> m;
// 初始化
memset(head, -1, sizeof(head));
edgeCnt = 0;
// 读取边并构建图
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
addEdge(u, v);
}
// 检测环
resetCycleDetection();
bool hasCycle = false;
for (int i = 1; i <= n; i++) {
if (vis[i] == 0) {
if (findCycle(i, -1)) {
hasCycle = true;
break;
}
}
}
// 输出结果
if (hasCycle) {
cout << "找到环,环的顶点为:";
for (int v : cycle) {
cout << v << " ";
}
cout << endl;
} else {
cout << "图中没有环" << endl;
}
return 0;
}
这段代码递归调用是在if判断里面
这段代码找到一个环就会停止
递归返回链:
- 当 DFS 在某个分支中发现环时(如从节点 u 访问到已标记的节点 v),会执行 return true。
- 这个返回值会逐层向上传递,终止所有上层递归调用。
- 例如:若 findCycle(v, u) 返回 true,则当前函数立即返回 true,不再继续遍历其他邻接边。
如果不想停止,取消那个if判断即可,然后开一个二维数组记录

浙公网安备 33010602011771号