当前位置:首页 > 洛谷 > 洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

3个月前 (07-03)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤) 洛谷题解 图论算法 Tarjan算法 C++ 连通分量 第1张

一、题目解读

洛谷1656题要求在无向图中找出所有割边(即删除后导致不连通的边)。题目核心在于判断图的连通性,并识别哪些边是“桥”。需理解图论中的连通分量概念,以及如何通过算法高效定位割边。

二、解题思路:Tarjan算法原理

采用经典的Tarjan算法求解割边。核心思想:

1. 通过深度优先搜索DFS)遍历图,记录每个节点的时间戳(dfn)和最小可到达祖先时间戳(low)。

2. 若节点u的子节点v满足low[v] > dfn[u],则(u,v)为割边(即v及其子无法通过其他路径回到u访问前的节点)。

3. 利用回边(反向边)更新low值,避免重复计算。

三、解题步骤

1. 建图:使用邻接表G存储无向图,读入n个节点和m条边,双向添加边(a,b)和(b,a)。

2. 初始化:时间戳timestamp置0,dfn和low数组清零。

3. 执行Tarjan算法:

○ 对每个未访问节点i,调用tarjan(i, -1),递归处理子树。

○ 递归中更新dfn和low,并判断割边条件。

4. 结果处理:将割边存入bridges(按节点值排序),最终输出。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 155;  
vector<int> G[MAXN];  // 邻接表存图
int dfn[MAXN], low[MAXN];
int timestamp = 0;     // 时间戳
vector<pair<int, int>> bridges; // 存储所有割边

// Tarjan核心函数,u为当前节点,father为父节点
void tarjan(int u, int father) {
    dfn[u] = low[u] = ++timestamp;  // 初始化dfn和low
    for (int v : G[u]) {            // 遍历u的所有邻接点
        if (!dfn[v]) {              // 未访问过的节点
            tarjan(v, u);           // 递归处理子节点
            low[u] = min(low[u], low[v]);  // 更新low值
            // 割边判断条件:子树无法通过回边到达u的祖先
            if (low[v] > dfn[u]) {
                bridges.push_back({min(u,v), max(u,v)});  
            }
        } else if (v!= father) {     // 处理回边(非父节点)
            low[u] = min(low[u], dfn[v]);  // 更新low值
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int a, b; cin >> a >> b;
        G[a].push_back(b);   // 双向建边
        G[b].push_back(a);
    }
    for (int i = 1; i <= n; ++i) {
        if (!dfn[i]) tarjan(i, -1);  // 遍历所有连通分量
    }
    sort(bridges.begin(), bridges.end());  // 按字典序排序
    for (auto &p : bridges) {
        cout << p.first << " " << p.second << endl;
    }
    return 0;
}

五、总结

Tarjan算法通过巧妙的时间戳与回边处理,高效识别割边,适用于稀疏图。关键点在于理解low值的含义(最小可到达祖先时间戳),以及割边条件的推导。本文代码简洁,注释清晰,为同类图论问题提供模板参考。建议结合实例调试,加深算法理解。

原创内容 转载请注明出处

分享给朋友:

相关文章

征服力扣704题:三步掌握经典二分查找算法

征服力扣704题:三步掌握经典二分查找算法

题目重解我们面对的是算法领域最经典的二分查找问题:在一个已排序的整数数组中,快速定位目标值的位置。就像在一本按字母顺序排列的字典中查找单词,我们不需要逐页翻阅,而是通过不断折半的方式快速缩小搜索范围,...

牛客14496题解:括号最大深度问题(栈思想与代码优化)

牛客14496题解:括号最大深度问题(栈思想与代码优化)

一、题目解读牛客14496题要求计算给定括号字符串中的最大深度。例如,对于字符串 "(()())",最大深度为2。题目考察对括号嵌套结构的理解,以及如何通过编程找到最深嵌套层次。二...

牛客NC67题解:汉诺塔递归算法与解题步骤

牛客NC67题解:汉诺塔递归算法与解题步骤

一、题目解读牛客NC67题要求解决汉诺塔问题,这是一个经典的递归算法题目。题目给定整数n,代表汉诺塔中的盘子数量,需要输出将n个盘子从起始柱移动到目标柱的所有步骤。汉诺塔问题规则为:每次只能移动一个盘...

洛谷2652题解析:同花顺排序问题的动态规划与滑动窗口优化

洛谷2652题解析:同花顺排序问题的动态规划与滑动窗口优化

一、题目解读洛谷2652题要求对一组扑克牌进行排序,目标是找到最少需要调整的次数,使得所有牌形成同花顺。题目中,扑克牌由花色和数字组成,需先按花色排序,再在同花色内按数字排序。核心难点在于如何处理花色...

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

一、题目解读洛谷P1121题要求求解环形数组的最大子段和,即在一个环形数组中找到一个连续子段,使其元素和最大。环形数组的特殊性在于首尾元素可相连,需考虑线性子段与跨越首尾的环形子段两种情况。二、解题思...

牛客232639题解析:双指针+排序算法高效求解三角形数量(附代码详解)

牛客232639题解析:双指针+排序算法高效求解三角形数量(附代码详解)

一、题目解读牛客232639题要求计算一个整数数组中能够组成有效三角形的三边组合数量。根据三角形不等式,三边需满足任意两边之和大于第三边。例如,数组[3, 4, 5, 6]可组成两个有效三角形([3,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。