tarjan算法求割点(java)

tarjan算法过程

思路很简单,如果某个dfs树里的点,它的所有后代的回边都不能连到这个点或这个点的上面,那么它就是割点。所以用dfn记录dfs序,然后low记录后代中回边里最优秀(连的点最靠上)的那个回边所到达的点。所以一个点是割点当且仅当满足下面条件之一:

  • (1) u为树根,且u有多于一个子树。
  • (2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,
    即u为v在搜索树中的父亲),使得dfn(u)<=low(v)。

另一种想法

也可以通过每个点必经点集的并集来确定割点,必经点集可以用逐步逼近的方法得到。但是迭代求必经点集的复杂度较高。

tarjan代码

import java.util.*;
public class Main {
    static final int NN=100100;
    static private class Graph{
    private
        Vector<Vector<Integer> > con;
        int[] artcltion;
        int[] vis_tarj;
        int[] dfn;
        int[] low;
        int n;
        int root;
        int cnt;
    public
        void init(int xx){
            n=xx;
            dfn=new int[NN];
            low= new int[NN];
            cnt=0;
            artcltion=new int[NN];
            vis_tarj =new int[NN];
            con=new Vector<Vector<Integer> >(NN);
            con.clear();
            for(int i=1;i<=n+10;i++){
                Vector<Integer> temp=new Vector<Integer>();
                temp.clear();
                con.addElement(temp);
            }
        }
        Graph(int xx){
            init(xx);
        }
        void addEdge(int x,int y){
            Vector <Integer> temp=new Vector<Integer>();
            temp=con.get(x);
            temp.addElement((Integer)y);
            con.set(x,temp);
            temp=con.get(y);
            temp.addElement((Integer)x);
            con.set(y,temp);
        }
        // void printGraph(){
        //     for(int i=1;i<=n;i++){
        //         for(int j=0;j<con.get(i).size();j++){
        //             System.out.printf("%d ",con.get(i).get(j));
        //         }
        //         System.out.printf("\n");
        //     }
        // }
        void tarjan(int st,int fa){
            dfn[st]=low[st]=++cnt;
            vis_tarj[st]=1;
            int sz=con.get(st).size();
            int numson=0;
            int res=0;
            for(int i=0;i<sz;i++){
                final int nex=con.get(st).get(i);
                if(vis_tarj[nex]==0){
                    numson++;
                    tarjan(nex,st);
                    low[st]=Math.min(low[st],low[nex]);
                    if(low[nex]>=dfn[st])res++;
                }
                else if(nex!=fa){
                    low[st]=Math.min(low[st],dfn[nex]);
                }
            }
            if(st==root){
                if(numson>=2){
                    artcltion[st]=1;
                }
            }
            else if(res>0){
                artcltion[st]=1;
            }
        }
        void solve(){
            for(int i=1;i<=n;i++){
                if(vis_tarj[i]==0){
                    root=i;
                    tarjan(i,-1);
                }
            }
        }
        void print_articulation(){
            int num=0;
            for(int i=1;i<=n;i++){
                if(artcltion[i]==1)num++;
            }
            System.out.println(num);
            for(int i=1;i<=n;i++){
                if(artcltion[i]==1)System.out.printf("%d ",i);
            }
            System.out.println();
        }
    };

    public static void main(final String[] args) throws Exception {
        final Scanner sc = new Scanner(System.in);
              
        int n=sc.nextInt();
        Graph G=new Graph(n);
        int m = sc.nextInt();
        for (int i = 1; i <= m; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            G.addEdge(x, y);
        }

        G.solve();
        G.print_articulation();   
       
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值