Tarjian算法c++模板

Tarjan算法是一种用于寻找图中强连通分量的算法,它可以在线性时间内完成这个任务。强连通分量是指在有向图中,任意两个顶点之间有路径相互可达的最大子图。

Tarjan算法的核心思想是使用深度优先搜索(DFS)来遍历图,同时维护一个栈来存储当前搜索路径上的顶点。当一个顶点无法继续前进时,我们从栈中弹出顶点,直到找到一个已经在栈中的顶点,这样就找到了一个强连通分量。

下面是Tarjan算法的一个C++实现:

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

// Tarjan算法寻找强连通分量的实现
class TarjanSCC {
private:
    int n; // 图中顶点的数量
    std::vector<std::vector<int>> adj; // 图的邻接表表示
    std::vector<int> ids; // 每个顶点的唯一标识符
    std::vector<int> low; // 顶点通过不经过父节点的最早的邻接点能够达到的最低标识符
    std::vector<bool> onStack; // 记录顶点是否在栈中
    std::stack<int> stack; // 用于存储顶点的栈
    int id = 0; // 当前的标识符
    int sccCount = 0; // 强连通分量的数量

    // 深度优先搜索
    void dfs(int at) {
        ids[at] = low[at] = id++;
        stack.push(at);
        onStack[at] = true;

        // 遍历邻接顶点
        for (int to : adj[at]) {
            if (ids[to] == -1) {
                dfs(to);
                low[at] = std::min(low[at], low[to]);
            } else if (onStack[to]) {
                low[at] = std::min(low[at], ids[to]);
            }
        }

        // 如果at是一个强连通分量的根
        if (ids[at] == low[at]) {
            while (!stack.empty()) {
                int node = stack.top();
                stack.pop();
                onStack[node] = false;
                low[node] = ids[at];
                if (node == at) {
                    break;
                }
            }
            sccCount++;
        }
    }

public:
    // 构造函数,接收图的邻接表
    TarjanSCC(const std::vector<std::vector<int>>& adj) : n(adj.size()), adj(adj) {
        ids.assign(n, -1);
        low.assign(n, 0);
        onStack.assign(n, false);

        // 对每个顶点调用DFS,如果它还没有被访问过
        for (int i = 0; i < n; i++) {
            if (ids[i] == -1) {
                dfs(i);
            }
        }
    }

    // 返回强连通分量的数量
    int getSCCCount() const {
        return sccCount;
    }

    // 返回每个顶点所属的强连通分量标识符
    std::vector<int> getLowestIds() const {
        return low;
    }
};

int main() {
    // 示例用法
    int n = 8;
    std::vector<std::vector<int>> adj(n);
    adj = {1};
    adj[1] = {2};
    adj[2] = {0};
    adj[3] = {1, 4};
    adj[4] = {5};
    adj[5] = {3, 6};
    adj[6] = {7};
    adj[7] = {6};

    TarjanSCC scc(adj);
    std::cout << "Number of Strongly Connected Components: " << scc.getSCCCount() << std::endl;
    std::vector<int> lowestIds = scc.getLowestIds();
    for (int i = 0; i < n; i++) {
        std::cout << "Vertex " << i << " belongs to SCC " << lowestIds[i] << std::endl;
    }

    return 0;
}

在这个实现中,我们定义了几个重要的成员变量:

  • n是图中顶点的数量。
  • adj是图的邻接表表示。
  • ids是每个顶点的唯一标识符,用于标识顶点在DFS遍历中的顺序。
  • low是顶点通过不经过父节点的最早的邻接点能够达到的最低标识符。
  • onStack是一个布尔数组,用于记录顶点是否在栈中。
  • stack用于存储顶点的栈。
  • id是当前的标识符,用于给顶点分配唯一的标识符。
  • sccCount是强连通分量的数量。

dfs函数中,我们首先给当前顶点分配一个唯一的标识符id,并将其压入栈中。然后,我们遍历邻接顶点,如果邻接顶点还没有被访问过,我们递归地调用dfs函数。如果邻接顶点已经在栈中(即它是当前搜索路径上的一个祖先),我们更新low[at]ids[to]的最小值。

当我们完成对顶点的所有邻接点的遍历时,如果ids[at]等于low[at],这意味着我们找到了一个强连通分量的根。我们从栈中弹出顶点,直到找到根节点,并将所有弹出的顶点标记为同一个强连通分量。

最后,在main函数中,我们创建了一个示例图,并调用TarjanSCC类来找到强连通分量。然后,我们输出强连通分量的数量,并打印出每个顶点所属的强连通分量标识符。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值