• Tarjan算法之割点


    定义

    (均在无向图中):在一个连通图中,如果有一个顶点,删除这个点以及相关的边之后,连通块的数量增多,我们就称这个顶点为割点.

    算法

    tarjan。设有点x及其子节点y,如果x不是是该连通图根节点,那么当且仅当存在dfn[x] <= low[y]时,x为割点。如x为根节点,则至少有满足上式的两个y才能保证x为割点。
    解释:

    1. x不为根节点,x把在x之前遍历的点和在x后遍历的点隔离,则去掉x会是原图不连通而新增连通块。
    2. x为根节点,存在至少两个y表明走任意一个y都不可能到达其他的y。那x被取走后y之间必然互相独立,增加新连通块。
      注意:由于判定符号是 <=,则不必考虑重边与父节点。

    例题 Luogu-P3388

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define lson x<<1
    #define rson x<<1|1
    #define ll long long
    #define rint register int
    #define mid ((st[x].l + st[x].r) >> 1)
    using namespace std;
    template <typename xxx> inline void read(xxx &x) {
    	char c = getchar(),f = 1;x = 0;
    	for(;c ^ '-' && !isdigit(c);c = getchar());
    	if(c == '-') c = getchar(),f = -1;
    	for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
    	x *= f;
    }
    template<typename xxx> inline void print(xxx x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    const int maxn = 100010;
    const int inf = 0x7fffffff;
    const int mod = 1e9 + 7;
    struct edge{
    	int to,last;
    }e[maxn<<1];
    int head[maxn],tot;
    inline void add(int from,int to) {
    	++tot;
    	e[tot].to = to;
    	e[tot].last = head[from];
    	head[from] = tot;
    } 
    int n,m;
    int dfn[maxn],low[maxn],cnt;
    int rt,cut[maxn];
    inline void tarjan(int x) {
    	low[x] = dfn[x] = ++cnt;
    	int ans = 0;
    	for(rint i = head[x];i;i = e[i].last) {
    		if(!dfn[e[i].to]) {
    			tarjan(e[i].to);
    			if(low[x] > low[e[i].to]) low[x] = low[e[i].to];
    			if(low[e[i].to] >= dfn[x]) {
    				++ans;
    				if(x ^ rt || ans > 1) cut[x] = 1;
    			}
    		} 
    		else if(low[x] > dfn[e[i].to]) low[x] = dfn[e[i].to];
    	}
    }
    int main()
    {
    	read(n);read(m);tot = 1;
    	for(rint i = 1;i <= m; ++i) {
    		int a,b;
    		read(a);read(b);
    		if(a == b) continue;
    		add(a,b);add(b,a);
    	}
    	for(rint i = 1;i <= n; ++i) {
    		if(!dfn[i]) {
    			rt = i;
    			tarjan(i);
    		}
    	}
    	int ans = 0;
    	for(rint i = 1;i <= n; ++i) if(cut[i]) ++ans;
    	print(ans),putchar('
    ');
    	for(rint i = 1;i <= n; ++i) {
    		if(cut[i]) print(i),putchar(' ');
    	}
    	return 0;
    }
    /*
    
    */
    
    
  • 相关阅读:
    Vue2 组件注册
    Vue2 CSS 过渡
    Vue2 过滤器
    Vue2 路由
    网页一次滚动一屏幕效果
    JavaScript作用域-声明提升(个人总结)
    JS函数作用域提升
    如何以计算机的方式去思考
    常用Git命令总结
    关于RBAC(Role-Base Access Control)的理解(转)
  • 原文地址:https://www.cnblogs.com/Thomastine/p/11779953.html
Copyright © 2020-2023  润新知