• 图论:tarjan相关算法复习


    参考博客:
    https://blog.csdn.net/izumi_hanako/article/details/78082544

    我以前的博客:
    https://blog.csdn.net/Cold_Chair/article/details/79918157


    1.割点

    对于一个无向连通图,如果有一个点(x),删掉它之后剩下的点就不连通了,它就是割点。

    随便以一个点(st)开始做tarjan,对于非起点的点(x eq st),如果有一个儿子(yin son[x])满足(low[y]>=dfn[x]),即(y)上不去了,那么(x)就是割点。

    对于起点(st),如果它在tarjan时有两个及以上的子树,它就是割点。


    2. 桥边

    对于一个无向连通图,如果有一个边((x,y)),删掉它之后就不连通了,它就是桥边。

    tarjan时有一条边:(x->y),若(low[y]>dfn[x]),则((x,y))是桥边。


    3. 有向图缩强联通分量

    dfs树上有三种边:

    1. 树边
    2. 返祖边
    3. 横插边

    在求(low)时,横插边忽略,只考虑树边和返祖边,所以需要记录哪些点在栈里。

    做完一个点(x)的子树后,若(low[x] ge dfn[x]),则栈顶到(x)的点可以缩成一个强联通分量。


    4. 无向图缩边双

    无向图没有横插边。

    同有向图缩强联通分量。

    注意遍历树时不能父亲过来的反向边,所以dfs时多记一下从哪条边来的。


    5. 无向图缩点双(圆方树)

    需要理解找桥边的过程先。

    如果有一个树边(x->y),满足(low[y] ge dfn[x]),那么目前栈顶到(y)的点和(x)就形成了一个点双。

    注意同样不能走父边。


    代码:

    1.https://www.luogu.com.cn/problem/P3388

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 2e5 + 5;
    
    int n, m, x, y;
    int fi[N], to[N * 2], nt[N * 2], tot = 1;
    
    void link(int x, int y) {
    	nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
    }
    
    int low[N], dfn[N], dfn0;
    int son[N], ans[N];
    
    void dg(int x, int la) {
    	low[x] = dfn[x] = ++ dfn0;
    	for(int i = fi[x]; i; i = nt[i]) if(i != la) {
    		int y = to[i];
    		if(!dfn[y]) {
    			dg(y, i ^ 1);
    			low[x] = min(low[x], low[y]);
    			son[x] ++;
    			if(low[y] >= dfn[x]) ans[x] = 1;
    		} else low[x] = min(low[x], dfn[y]);
    	}
    	if(la == 0 && son[x] <= 1) ans[x] = 0;
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	fo(i, 1, m) {
    		scanf("%d %d", &x, &y);
    		link(x, y); link(y, x);
    	}
    	fo(i, 1, n) if(!dfn[i])
    		dg(i, 0);
    	int s0 = 0;
    	fo(i, 1, n) s0 += ans[i];
    	pp("%d
    ", s0);
    	fo(i, 1, n) if(ans[i]) pp("%d ", i);
    }
    

    3.https://www.luogu.com.cn/problem/P3387

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 1e5 + 5;
    
    int n, m, a[N], x, y;
    int fi[N], nt[N], to[N], tot;
    
    void link(int x, int y) {
    	nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
    }
    
    int low[N], dfn[N], dfn0;
    int bz[N], z[N], z0;
    
    int id[N], id0, v[N];
    
    vector<int> p[N], e[N];
    #define pb push_back
    #define si size()
    
    void dg(int x) {
    	low[x] = dfn[x] = ++ dfn0;
    	z[++ z0] = x; bz[x] = z0;
    	
    	for(int i = fi[x]; i; i = nt[i]) {
    		int y = to[i];
    		if(!dfn[y]) {
    			dg(y);
    			low[x] = min(low[x], low[y]);
    		} else if(bz[y]) low[x] = min(low[x], dfn[y]);
    	}
    	
    	if(low[x] >= dfn[x]) {
    		id0 ++;
    		do {
    			bz[z[z0]] = 0;
    			id[z[z0]] = id0;
    			p[id0].pb(z[z0]);
    			v[id0] += a[z[z0]];
    		} while(z[z0 --] != x);
    	}
    }
    
    int r[N], d[N], d0;
    
    int f[N];
    
    int main() {
    	scanf("%d %d", &n, &m);
    	fo(i, 1, n) scanf("%d", &a[i]);
    	fo(i, 1, m) {
    		scanf("%d %d", &x, &y);
    		link(x, y);
    	}
    	fo(i, 1, n) if(!dfn[i])
    		dg(i);
    	fo(i, 1, id0) {
    		ff(_x, 0, p[i].si) {
    			int x = p[i][_x];
    			for(int j = fi[x]; j; j = nt[j]) {
    				int y = to[j];
    				if(i != id[y]) {
    					e[i].pb(id[y]);
    				}
    			}
    		}
    	}
    	fo(i, 1, id0) {
    		ff(_j, 0, e[i].si) {
    			int j = e[i][_j];
    			r[j] ++;
    		}
    	}
    	fo(i, 1, n) if(!r[i]) {
    		d[++ d0] = i;
    	}
    	for(int i = 1; i <= d0; i ++) {
    		int x = d[i];
    		ff(_j, 0, e[x].si) {
    			int y = e[x][_j];
    			if(!(-- r[y])) d[++ d0] = y;
    		}
    	}
    	int ans = 0;
    	fd(i, d0, 1) {
    		int x = d[i];
    		ff(_j, 0, e[x].si) {
    			int y = e[x][_j];
    			f[x] = max(f[x], f[y]);
    		}
    		f[x] += v[x];
    		ans = max(ans, f[x]);
    	}
    	pp("%d
    ", ans);
    }
    
    void tar(int x, int la) {
        d[++ d[0]] = x; low[x] = dfn[x] = ++ td;
        for(int i = final[x]; i; i = next[i]) if(i != (la ^ 1)){
            int y = to[i];
            if(!dfn[y]) tar(y, i), low[x] = min(low[x], low[y]); else
            low[x] = min(low[x], dfn[y]);
        }
        if(dfn[x] == low[x]) {
            tz ++;
            do to[d[d[0]]] = tz; while(d[d[0] --] != x);
        }
    }
    
    void tar(int x, int la) {
        dfn[x] = low[x] = ++ tt;
        z[++ z[0]] = x;
        for(int i = e.final[x]; i; i = e.next[i]) {
            int y = e.to[i];
            if(!dfn[y]) {
                tar(y, i);
                low[x] = min(low[x], low[y]);
                if(low[y] >= dfn[x]) {
                    td ++;
                    while(z[z[0]] != y) e2.link(z[z[0] --], td);
                    e2.link(z[z[0] --], td); e2.link(x, td);
                }
            } else if(i != (la ^ 1)) low[x] = min(low[x], dfn[y]);
        }
    }
    
  • 相关阅读:
    恶意代码分析
    免杀原理与实践
    GIT安装及IDEA配置(GIT)
    Idea导入本地Mavenue项目
    Redis在linux安装部署(单机版)
    python数据科学导论--读书笔记01
    廖雪峰Python3 学习笔记--切片、迭代、列表生成式、生成器、迭代器
    廖雪峰Python3 学习笔记--函数参数(默认参数、可变参数、关键字参数)
    廖雪峰Python3 学习笔记--编码
    廖雪峰Python3 学习笔记--变量常量
  • 原文地址:https://www.cnblogs.com/coldchair/p/13432343.html
Copyright © 2020-2023  润新知