• Tarjan全家桶


    强联通分量及缩点

    #include<bits/stdc++.h>
    #define re register
    #define v e[i].to
    using namespace std;
    const int lzw=1e4+3;
    int n,m,head[lzw],tot,h[lzw],cnt,dfn[lzw],low[lzw],belong[lzw],stk[lzw],top,dfn_clock,scc_cnt,in[lzw];
    struct edge{
    	int to,next;
    }e[lzw*10],ee[lzw*10];
    void add(int a,int b){
    	e[++tot].to=b;
    	e[tot].next=head[a];
    	head[a]=tot;
    }
    void insert(int a,int b){
    	ee[++cnt].to=b;
    	ee[cnt].next=h[a];
    	h[a]=cnt;
    }
    void tarjan(int u){//强联通分量
    	dfn[u]=low[u]=++dfn_clock,stk[++top]=u;
    	for(re int i=head[u];i;i=e[i].next){
    		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    		else if(!belong[v]) low[u]=min(low[u],dfn[v]);
    	}
    	if(low[u]==dfn[u]){
    		scc_cnt++;
    		while(1){
    			int tmp=stk[top--];
    			belong[tmp]=scc_cnt;
    			if(tmp==u) break;
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(re int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    	}
    	for(re int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    	for(re int j=1;j<=n;j++){//缩点
    		for(re int i=head[j];i;i=e[i].next){
    			if(belong[v]==belong[j]) continue;
    			insert(belong[j],belong[v]),in[belong[v]]++;
    		}
    	}
    	return 0;
    }
    

    割点

    (large {color{red} {注意判根!}})

    void tarjan(int u,int fa){
          dfn[u]=low[u]=++dfn_clock;
    	int ch=0;
    	for(re int i=head[u];i;i=e[i].next){
    		if(!dfn[v]){
    			tarjan(v,u),low[u]=min(low[v],low[u]);
    			if((!fa&&++ch>1)||(fa&&low[v]>=dfn[u])) cut[u]=1;
    		}
    		else if(v!=fa) low[u]=min(low[u],dfn[v]);
    	}
    }
    

    点双联通分量

    void tarjan(int u,int fa){
    	dfn[u]=low[u]=++dfn_clock;
    	stk[++top]=u;
    	for(re int i=head[u];i;i=e[i].next){
    		if(v==fa) continue;
    		if(!dfn[v]){
    			tarjan(v,u);
    			low[u]=min(low[u],low[v]);
    			if(low[v]>=dfn[u]){
    				bcc_cnt++;
    				while(1){
    					int tmp=stk[top--];
    					all[bcc_cnt].push_back(tmp);
    					if(tmp==v) break;
    				}
    				all[bcc_cnt].push_back(u);
    			}
    		}else low[u]=min(low[u],dfn[v]);
    	}
    }
    

    void tarjan(int u,int fa){
    	dfn[u]=low[u]=++dfn_clock;
    	for(re int i=head[u];i;i=e[i].next){
    		if(v==fa) continue;
    		if(!dfn[v]){
    			tarjan(v,u);
    			low[u]=min(low[u],low[v]);
    			if(low[v]>dfn[u]) e[i].flag=e[i^1].flag=1;
    		}else low[u]=min(low[u],dfn[v]);
    	}
    }
    

    边双联通分量

    桥的部分再加上(DFS)

    void dfs(int u){
    	belong[u]=cnt,vis[u]=1;
    	for(re int i=head[u];i;i=e[i].next) if((!e[i].flag)&&(!vis[v])) dfs(v);
    }
    
  • 相关阅读:
    es6 数组的扩展
    面向对象的7大原则及其实例
    flex 布局
    一、创建vue
    箭头函数
    destructuring
    spreed&rest
    变量新声明之let、const
    jQuery之遍历索引相关方法
    jQuery之位置坐标图形相关方法
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/13930694.html
Copyright © 2020-2023  润新知