Tarjan的几个关键点:
1.DFS基本思路:先访问当前节点,标记为已访问,之后DFS相邻节点。
2.Stack储存节点,遍历过程中每个节点记录time(时间戳),low数组(标识每个强连通分量)
3.边界条件:当一个节点没有后驱节点此节点 (即他的dfn=他的low)时。
4.存图:list或者邻接矩阵
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Stack;
public class Main {
private static ArrayList[] list ;
private static int[] dfn ;
private static int[] low ;
private static int[] instack ;
private static int[] vis ;
private static int time,sum ;
private static Stack<Integer> stack ;
private static void Tarjan(int i){
dfn[i] = low[i] = ++time ;
stack.push(i) ;
instack[i] = 1 ;
for(int j=0;j<list[i].size();j++){
int k = (int)list[i].get(j) ;
if(vis[k]==0){
vis[k]=1 ;
Tarjan(k) ;
low[i] = Math.min(low[i],low[k]) ;
}else if(instack[k]==1){
low[i] = Math.min(low[i],dfn[k]) ;
}
}
if(low[i]==dfn[i]){
sum++ ;
int k ;
do{
k = stack.pop() ;
instack[k] = 0 ;
}while(i!=k&&!stack.isEmpty()) ;
}
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))) ;
while(in.nextToken()!=StreamTokenizer.TT_EOF){
int N = (int)in.nval ;
in.nextToken() ;
int M = (int)in.nval ;
if(N==0&&M==0)break ;
list = new ArrayList[N+1] ;
for (int i = 0; i <= N; i++) {
list[i] = new ArrayList<Integer>() ;
}
for (int i = 0; i < M; i++) {
in.nextToken() ;
int x = (int)in.nval ;
in.nextToken() ;
int y = (int)in.nval ;
list[x].add(y) ;
}
dfn = new int[N+1] ;
low = new int[N+1] ;
time = 0 ;
sum = 0 ;
stack = new Stack<>();
instack = new int[N+1] ;
vis = new int[N+1] ;
int h = 0 ;
for(int i=1;i<=N;i++){
if(vis[i]==0){
vis[i] = 1 ;
h++ ;
if(h>=2){
sum = 2 ;
break ;
}
Tarjan(i) ;
}
}
if(sum==1){
System.out.println("Yes") ;
}else{
System.out.println("No") ;
}
}
}
}