tarjan求桥

tarjan求桥

定义

1、强连通:
在有向图G中,如果两个顶点u,v间有一条从u到v的有向路径,同时还有一条从v到u的有向路径,则称两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向非强连通图的极大强连通子图,称为强连通分量。
2、桥:
在图中,如果删除一条边使得这个图分成了两个图(没有其他边连通),我们就称这条边为桥

例题

P1656 炸铁路

题目大意:

在一个图中,炸掉一条边,使得某两个点没有路径相连。

思路:

题意要求出图上所以的桥
我们可以先设出两个数组:
1、\(dfn_i\) 表示\(i\)点的时间戳(点\(i\)是第几个被访问的点)
2、\(low_i\) 与点\(i\)能到达所有点的时间戳的最小值(不包括\(i\)的父亲
当原图上的边连接两个端点\(father和son\):
显然,当\(dfn_{father} < low_{son}\)时这条边为桥

code:

#include<bits/stdc++.h>
#define LL long long 
#define inl inline
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
using namespace std;
const int N = 155 , M = 5005;
int dfn[N] , low[N] , n , m , ct , cnt = 1 , hd[N] , flag[M << 1];
struct E {
    int to , fr , nt;
}e[M << 1];
struct Pr {
    int fr , to;
}pr[M << 1];
inl void add (int x , int y) {
    e[++cnt].to = y , e[cnt].fr = x , e[cnt].nt = hd[x] , hd[x] = cnt;
}
inl int read () {
    int val = 0, fu = 1;
    char ch = getchar ();
    while (ch < '0' || ch > '9') {
        if (ch == '-') fu = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <='9') {
        val = val * 10 + (ch - '0');
        ch = getchar ();
    }
    return val * fu;
}
inl void dfs (int x , int fa) {
    dfn[x] = low[x] = ++ct;
    int y;
    for (int i = hd[x] ; i ; i = e[i].nt) {
        y = e[i].to;
        if (!dfn[y]) {
            dfs (y , x);
            low[x] = min (low[x] , low[y]);
            if (low[y] > dfn[x]) {
                flag[i] = flag[i ^ 1] = 1;
            }
        }
        else if (y != fa) {
            low[x] = min (low[x] , dfn[y]);
        }
    }
}
inl bool comp (Pr x , Pr y) {
    if (x.fr < y.fr) return 1;
    else if (x.fr == y.fr && x.to < y.to) return 1;
    else return 0; 
}
int main () {
    int u , v;
    n = read () , m = read ();
    fu(i , 1 , m) {
        u = read () , v = read ();
        add (u , v);
        add (v , u);
    }
    fu(i , 1 , n) {
        if (dfn[i]) continue;
        dfs (i , 0);
    }
    ct = 0;
    for (int i = 2 ; i <= cnt ; i += 2) {
        int x = min (e[i].fr , e[i].to) , y = max (e[i].fr , e[i].to);
        if (flag[i]) {
            pr[++ct].fr = x , pr[ct].to = y;  
        }
    }
    sort (pr + 1 , pr + ct + 1 , comp);
    fu(i , 1 , ct) {
        printf ("%d %d\n" , pr[i].fr , pr[i].to);
    }
    return 0;
}
posted @ 2023-04-01 10:08  2020fengziyang  阅读(33)  评论(0编辑  收藏  举报