求割点 割边 Tarjan

附上一般讲得不错的博客 https://blog.csdn.net/lw277232240/article/details/73251092

https://www.cnblogs.com/collectionne/p/6847240.html

https://blog.csdn.net/zhn_666/article/details/77971619

然后附上模板题:              https://vjudge.net/problem/HihoCoder-1183

裸题,直接要你输出割点 和 割边.. 唯一坑点就是割边的输出..自己看题.

#include <set>
#include <cstdio>
#include <algorithm>

using namespace std;

struct Point {
    int u;
    int v;
    Point () { }
    Point (int uu, int vv) : u(uu), v(vv) { }
    bool operator < (const Point &a) const {
        if (u != a.u) return u < a.u;
        return v < a.v;
    }
};

struct Edge {
    int lst;
    int to;
}edge[200500];
int head[20500];
int qsz = 1;

inline void add(int u, int v) {
    edge[qsz].lst = head[u];
    edge[qsz].to  = v;
    head[u] = qsz++;
}

int  dfn[20500];
int  low[20500];
//int   pa[20500];
int  dfn_num;
set<int> ans;
set<Point> ans_pt;
/*
void Tarjan(int u) {
    int i, v, child = 0;
    dfn[u] = low[u] = ++dfn_num;
    for (i=head[u]; i; i=edge[i].lst) {
        v = edge[i].to;
        if (v == pa[u]) continue;
        if (!dfn[v]) { // 树边, 父子边
            pa[v] = u;
            Tarjan(v);
            child++;
            low[u] = min(low[u], low[v]);
            //  case 1 u是根节点,同时只是有2颗子树---> 无向图 所以可能有多个根节点.
            if (!pa[u] && child>=2) ans.insert(u) ;  // 根节点是否有多颗子树.. 注意 这个是写在if (!vis[u])里面的.
            //  case 2 u是叶子节点, 割点条件是low[v]>=dfn[u]
            if ( pa[u] && low[v] >= dfn[u]) ans.insert(u); // 说明v无法连接到u的祖先.
            //  桥 的条件是: low[v] > dfn[u]
            if (low[v] > dfn[u]) ans_pt.insert(Point(min(u, v), max(v, u))); // 说明v无法连接到u或者u的祖先.
        } else {
            low[u] = min(low[u], dfn[v]);  // u v 为回边
        }
    }
}
*/
void Tarjan(int u, int fa) {
    int i, v, child = 0;
    dfn[u] = low[u] = ++dfn_num;
    for (i=head[u]; i; i=edge[i].lst) {
        v = edge[i].to;
        if (v == fa) continue;
        if (!dfn[v]) { // 树边, 父子边
            Tarjan(v, u);
            child++;
            low[u] = min(low[u], low[v]);
            //  case 1 u是根节点,同时只是有2颗子树---> 无向图 所以可能有多个根节点.
            if (fa==u && child>=2) ans.insert(u) ;  // 根节点是否有多颗子树.. 注意 这个是写在if (!vis[u])里面的.
            //  case 2 u是叶子节点, 割点条件是low[v]>=dfn[u]
            if (fa!=u && low[v] >= dfn[u]) ans.insert(u); // 说明v无法连接到u的祖先.
            //  桥 的条件是: low[v] > dfn[u]
            if (low[v] > dfn[u]) ans_pt.insert(Point(min(u, v), max(v, u))); // 说明v无法连接到u或者u的祖先.
        } else {
            low[u] = min(low[u], dfn[v]);  // u v 为回边
        }
    }
}

int main()
{
//    freopen("E:\\input.txt", "r", stdin);
    int n, m;
    int u, v, i, j;
    scanf("%d%d", &n, &m);
    for (i=1; i<=m; ++i) {
        scanf("%d%d", &u, &v);
        add(u, v);
        add(v, u);
    }
    Tarjan(1, 1);

    if (ans.size()) {
        bool flag = true;

        for (auto iter : ans) {
            if (flag) {
                printf("%d", iter);
                flag = false;
            } else printf(" %d", iter);
        }
    } else {
        printf("Null");
    }
    printf("\n");
    for (auto iter : ans_pt)
        printf("%d %d\n", iter.u, iter.v);    

    return 0;
}

连通度 : 连通图的连通程度. 分为点连通 和 边连通.

割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点就是割点。
割边:在连通图中,删除了连通图的某条边后,图不再连通。这样的边被称为割边,也叫做桥。

DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树。

树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边
回边:在搜索树中的橙色线所示,可理解为在DFS过程中遇到已访问节点时所经过的边,也称为返祖边、后向边

求割点 割边(桥)

注意 low[]和求连通分量的意义不同

求连通分量的low[]的意思是,节点u能访问的最小时间戳

求割点 桥 的low[]的意思是  节点u或u的子树通过回边追溯到最早的祖先节点

void Tarjan(int u, int fa) {
    int i, v, child = 0;
    dfn[u] = low[u] = ++dfn_num;
    for (i=head[u]; i; i=edge[i].lst) {
        v = edge[i].to;
        if (v == fa) continue;
        if (!dfn[v]) { // 树边, 父子边
            Tarjan(v, u);
            child++;
            low[u] = min(low[u], low[v]);
            //  case 1 u是根节点,同时只是有2颗子树---> 无向图 所以可能有多个根节点.
            if (fa==u && child>=2) ans.insert(u) ;  // 根节点是否有多颗子树.. 注意 这个是写在if (!vis[u])里面的.
            //  case 2 u是叶子节点, 割点条件是low[v]>=dfn[u]
            if (fa!=u && low[v] >= dfn[u]) ans.insert(u); // 说明v无法连接到u的祖先.
            //  桥 的条件是: low[v] > dfn[u]
            if (low[v] > dfn[u]) ans_pt.insert(Point(u, v)); // 说明v无法连接到u或者u的祖先.
        } else {
            low[u] = min(low[u], dfn[v]);  // u v 为回边
        }
    }
}

原文地址:https://www.cnblogs.com/cgjh/p/9557760.html

时间: 2024-10-10 15:14:24

求割点 割边 Tarjan的相关文章

tarjan求割点割边的思考

这个文章的思路是按照这里来的. 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 一,根节点如果有两颗及以上子树,它就是割点.这个应该说是显然的. 二,对于普通的结点a,如果它递归树的子树中,有任意节点b的low[b]<dfn[a],那么它就不是割点,反之则是割点. 我们先来证明如果low[b]<dfn[a],a一定不是割点.low[b]<dfn[a]说明有一个结点,通过非树枝边可以访问到a以前的结点,那么显然去掉a以后,b依然与a以上的递归树联通,a不是割

求割点 割边

Tarjan void Tarjan(int u, int fa) { int i, v, child = 0; dfn[u] = low[u] = ++dfn_num; for (i=head[u]; i; i=edge[i].lst) { v = edge[i].to; if (v == fa) continue; if (!dfn[v]) { // 树边, 父子边 Tarjan(v, u); child++; low[u] = min(low[u], low[v]); // case 1

[UVA315]Network(tarjan, 求割点)

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=251 求割点,除了输入用strtok和sscanf处理输入以外,对于求割点的tarjan算法有了进一步理解. 特别注意88行,如果u是根并且至少两个儿子,那它一定是割点无误,还有第二个情况用如图代表: 这个例子里显然:low[4]=2,dfn[4]=4,dfn[3]=3.现dfs到

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

本文转载自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在阅读本文之前,请确保您已经理解并掌握了基本的Tarjan算法,不会的请到http://hi.baidu.com/lydrainbowcat/blog/item/42a6862489c98820c89559f3.html阅读.   基本概念:   1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如

poj Transferring Sylla(如何快速的判断一个图是否是3—连通图,求割点,割边)

Transferring Sylla 首先,什么是k连通图?k连通图就是指至少去掉k个点使之不连通的图. 题目: 题目描述的很裸,就是给你一张图要求你判断这图是否是3-连通图. 算法分析: ///////////////////////////////////////////////////////////////////// (网上别人的分析,分析的很好所以直接引用了) 考虑一下不可行的情况,就是存在两点间的路径条数<3情况,那么我们可以去枚举两个点a和b,然后将其和相邻的边删除,然后判断联通

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最小割边集合中的边数.

Tarjan&amp;割点&amp;割边&amp;点双&amp;边双&amp;缩点

文末有福利. Tarjan是通过搜索树和压栈完成的,维护两个东西:dfn[i](时间戳).low[i](通过搜索树外的边i(返祖边),节点能到达的最小节点的时间戳). 跑完Tarjan,缩点,可以得到DAG图(有向无环图),可以再建图或统计入度出度. 在有向图中,可以找强连通分量SCC(极大强联通子图)(任意两点可以互达): 多维护一个vis[i]表示在不在栈中. 1 void tarjan_(int u) 2 { 3 stack[++tp]=u; 4 dfn[u]=low[u]=++num;