首先给大家一个网址讲的比较细:http://www.cnblogs.com/en-heng/p/4002658.html
如果还有不懂的话,可以回来再看看我的文章;
概念明确:
low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点
用那个网址的例子,我给大家推演一下tarjan的dfn和low;
A的dfn和low均为1;
B:low = 1(通过B->A的回边)
C: low = 1(通过C->A的回边)
D:low = (B的dfn)5,(通过D->B的回边)
E:low = 5,(通过E->B的回边)
F:low = 1(通过F->A的回边)
G:low = 5(通过G->B的回边)
H:low = 5(通过H->B的回边)
例题可以参考cojs921
http://cojs.tk/cogs/problem/problem.php?pid=921
代码如下
#include<cstdio>
const int maxn = 5010 ;
using namespace std;
inline void read(int &x){
x=0;char ch;
while(ch=getchar(),ch<'!');
while(x=10*x+ch-'0',ch=getchar(),ch>'!');
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
struct Edge{
int to,next;
}G[100100];
int tot,head[maxn],scc_cnt,dfs_cnt;
int dfn[maxn],low[maxn],sccno[maxn];
int sta[maxn],top,num[maxn];
void add(int u,int v){
G[++tot].to=v;
G[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u){
low[u]=dfn[u]=++dfs_cnt;
sta[++top]=u;
for(int i=head[u];i;i=G[i].next){
int to=G[i].to;
if(!dfn[to]){
tarjan(to);
low[u]=cat_min(low[u],low[to]);
}
else if(!sccno[to]) low[u]=cat_min(low[u],dfn[to]);
}
if(low[u]==dfn[u]){
scc_cnt++;
while(1){
int x=sta[top--];
sccno[x]=scc_cnt;
num[scc_cnt]++;
if(x==u) break;
}
}
}
int main(){
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
int n;read(n);
int m;read(m);
int x,y,op;
for(int i=1;i<=m;i++){
read(x),read(y),read(op);
add(x,y);
if(op==2) add(y,x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
int max1=0,pos=0;
for(int i=1;i<=scc_cnt;i++){
if(num[i]>max1){
max1=num[i];
pos=i;
}
}
printf("%d
",max1);
for(int i=1;i<=n;i++){
if(sccno[i]==pos){
printf("%d ",i);
}
}
fclose(stdin);fclose(stdout);
return 0;
}