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();
}
}