zoukankan      html  css  js  c++  java
  • 无向图的tarjan算法

    -无向图求点双联通分量 并求单环
    暂时还不知道有什么用因为不能缩点 但是好像有用
    将桥和割点分开讨论
    注意判断根是否为割点

    stack<int> W;
    ll f[maxnn];
    int scc=0;
    ll sum[maxnn];
    int ttt[maxnn];
    int ma[maxnn],mi[maxnn];
    void tarjan(int v,int fa) {
        int r;
        mark[v]=1;
        dfn[v]=low[v]=++vis;
        W.push(v);
        for(int i=las[v]; i; i=nex[i]) {
            int u=en[i];
            int d;
            if(u!=fa) {
                if(!dfn[u]) {
                    tarjan(u,v);
                    low[v]=min(low[v],low[u]);
                    if(dfn[v]==low[u]) {
                        scc++;
                        mi[scc]=v;
                        rrr[scc]=1;
                        ma[scc]=v;
                        do {
    						d=W.top();
    						rrr[scc]++;
                            mi[scc]=min(mi[scc],d);
                            ma[scc]=max(ma[scc],d);
                            W.pop();
                        } while(d!=u);
                    }
                    if(dfn[v]<low[u]) {
                        do {
                        	
    						d=W.top();
                            W.pop();
                        } while(d!=u);
                    }
                } else {
                    low[v]=min(low[v],dfn[u]);
                }
            }
        }
    }
    
    int Tarjan(int u, int fa)
    {
    int low[u] = dfn[u] = ++Time;
    for(int i = Last[u]; i; i = Next[i])
    {
    Son[u]++;
    int v = End[i];
    if(!dfn[v])
    {
    s.push(i); //i号边入栈, i是一条父子边(树枝边)
    Tarjan(v, u);
    low[u] = min(low[u], low[v]);
    if(low[v] >= dfn[u]) //对于v而言,u是割点,找到一个点双连通分量
    {
    CutPoint[u] = true; //将u标记为是割点
    BCC++; //统计双连通分量的个数
    while(true)
    {
    int k = s.top(); s.pop(); //弹出栈顶边, 编号为k
    int x=Start[k]; int y=End[k]; //x,y分别为k号边的两个端点
    if(Belong[x]!=BCC) //Belong[x]记录目前x属于那个双连通块
    { Block[BCC].push_back(x); Belong[x]=BCC; } //Block[BCC]存储属于BCC号联通块的节点的编号
    if(Belong[y]!=BCC)
    { Block[BCC].push_back(y); Belong[y]=BCC; }
    if(x==u && y==v )break; //对于v,u是割点,那么v肯定不属于当前连通块
    }
    }
    }e
    lse if(dfn[v] < dfn[u] && v != fa) //i是一条返祖边
    {
    s.push(i);
    low[u] = min(low[u], dfn[v]);
    }
    }i
    f(fa == 0 && Son[u] <= 1) CutPoint[u] = false; //前面可能误把根当作了割点。 若i为根, 且儿子个数<=1,i不是割点。
    }
    

    -无向图求边双联通分量 强行变成有向图

    
    stack<int > S;
    int sec;
    inline void tarjan(int v,int e) {
    	dfn[v]=low[v]=++vii;
    	S.push(v);
    	for(int i=las[v]; i; i=nex[i]) {
    		if((e!=-1)&&((i^1)==(e))) {
    			continue;
    		}
    		ll u=en[i];
    		if(!dfn[u]) {
    			tarjan(u,i);
    			low[v]=min(low[u],low[v]);
    		} else {
    			low[v]=min(low[v],dfn[u]);
    		}
    	}
    	ll r;
    	if(low[v]==dfn[v]) {
    		sec++;
    		do {
    			r=S.top();
    			S.pop();
    			belong[r]=sec;
    			ttt[sec]++;
    		} while(r!=v);
    	}
    }
    
    
  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11789289.html
Copyright © 2011-2022 走看看