• tarjan求割点和割边


    概念

    割点 :在一个无向图中,如果删除某个顶点,这个图就不再连通(任意两点之间无法相互到达),那么这个顶点就是这个图的割点。

    割边(桥):在一个无向图中删除某条边后,图不再连通,那么这条边就是这个图的割边(也叫作桥)

    求法

    • 割点: 一个顶点(x)是割点,当且仅当满足:
    1. (x)为树根,且(x)有多于一个子树。

    2. (x)不为树根,且满足(x)(to)在搜索树中的父亲,并使得(low_{to}le dfn_x).(因为删去(x)(to)以及(to)的子树不能到达(x)的其他子树以及祖先)

    code:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a; 
    }
    const int maxn = 1e5+10;
    int n,m;
    struct node{
    	int to,next;
    }ed[maxn*2];
    int head[maxn*2],tot;
    void add(int u,int to){
    	ed[++tot].to = to;
    	ed[tot].next = head[u];
    	head[u] = tot;
    }
    int dfn[maxn],low[maxn],flag[maxn],cnt,child;
    void tarjan(int x,int fa){
    	dfn[x] = low[x] = ++cnt;
    	for (int i = head[x];i;i = ed[i].next){
    		int to = ed[i].to;
    		if (!dfn[to]){
    			tarjan(to,fa);
    			low[x] = min(low[x],low[to]);
    			if (low[to] >= dfn[x]&&x != fa) flag[x] = 1;	
    			if (x == fa) child++;
    		}
    		low[x] = min(low[x],dfn[to]);
    	}
    	if (child >= 2&&x == fa) flag[x] = 1;
    }
    int main(){
    	n = read(),m = read();
    	for (int i = 1;i <= m;i++){
    		int x = read(),y = read();
    		add(x,y),add(y,x);
    	}
    	for (int i = 1;i <= n;i++){
    		if (!dfn[i]) child = 0,tarjan(i,i);
    	}
    	int tot = 0;
    	for (int i = 1;i <= n;i++){
    		if (flag[i]) tot++;
    	}
    	printf("%d
    ",tot);
    	for (int i = 1;i <= n;i++){
    		if (flag[i]) printf("%d ",i);
    	}
    	return 0;
    } 
    
    • 割边:
    1. 一条无向边((x,to))是桥,满足(low_{to}>dfn_x).(因为(to)想要到达(x)的父亲必须经过((x,to))这条边,所以删去这条边图不连通)

    2. 实现时因为是无向图,建反边两条边都要标记上,边从(1)开始编号,正向边(x)的反向边就是(x)^(1)

    code:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 3e6+10;
    int n,m;
    struct node{
    	int to,next;
    }ed[maxn*2];
    int head[maxn*2],tot = 1;
    void add(int u,int to){
    	ed[++tot].to = to;
    	ed[tot].next = head[u];
    	head[u] = tot;
    }
    int dfn[maxn],low[maxn],cnt,res;
    int bridge[maxn];
    void tarjan(int x, int fa) {
        dfn[x] = low[x] = ++cnt;
        for (int i = head[x];i;i = ed[i].next) {
            int to = ed[i].to;
            if (!dfn[to]) {
                tarjan(to, i);
                low[x] = min(low[x],low[to]);
                if (low[to] > dfn[x])
                    bridge[i] = bridge[i^1] = true;
            }
            else if (i != (fa^1)) low[x] = min(low[x],dfn[to]);
        }
    }
    int main(){
    	n = read(),m = read();
    	for (int i = 1;i <= m;i++){
    		int u = read(),v = read();
    		add(u,v),add(v,u);
    	}
    	for (int i = 1;i <= n;i++){
    		if (!dfn[i]) tarjan(i,0);
    	}
    	int res = 0;
        for (int i = 2; i < tot; i+=2)
            if (bridge[i]) res++;
    	printf("%d
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    CF598E Chocolate Bar 题解 动态规划
    CF864E Fire 题解 背包DP
    用 程序 解决 windows防火墙 的 弹窗 问题
    windbg 使用与技巧
    bat 下 字符串拆分 类似 split 可以使用 for /f delims
    vs2013 在按F5调试时,总是提示 “项目已经过期”的解决方案
    代理与反向代理
    关于维护用户状态的一致性
    视频的裁剪后缩放功能。
    通信协议的设计
  • 原文地址:https://www.cnblogs.com/little-uu/p/13954408.html
Copyright © 2020-2023  润新知