前向星存图之环的判断与记录

基本思路是:

  • 使用 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判断即可,然后开一个二维数组记录
posted @ 2025-07-07 17:00  暂未成功人士  阅读(10)  评论(0)    收藏  举报