核心思想:寻找桥边
记录dfn,与low 表示当前节点的时间戳 ,与能追溯到的最早祖先的时间戳
当且仅当dfn[x]<low[y]的时候,x,y的边是桥边
因为y怎么上都到不了x
如果当前节点编号不等于上一条走的编号(说明不是一条路)
那么就可以更新时间戳
找出桥边后再dfs一遍就好了
#include<bits/stdc++.h>
#define N 20005
#define M 500005
using namespace std;
int n,m;
int first[N],next[N],to[N],w[N],tot=1;
int dfn[N],low[N],sum,id[N],bridge[M],sign;
int read(){
int cnt=0;char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
void add(int x,int y,int z){
next[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}
void tarjan(int cur,int in_E){
dfn[cur]=low[cur]=++sign;
for(int i=first[cur];i;i=next[i]){
int t=to[i];
if(!dfn[t]){
tarjan(t,i);
low[cur]=min(low[cur],low[t]);
if(low[t]>dfn[cur]){
bridge[i]=bridge[i^1]=1;
}
}
else if(i!=(in_E^1)){
low[cur]=min(low[cur],dfn[t]);
}
}
}
void Make_id(int cur,int Id){
id[cur]=Id;
for(int i=first[cur];i;i=next[i]){
int t=to[i];
if(id[t]||bridge[i]) continue;
Make_id(t,Id);
}
}
int main(){
freopen("1.in","r",stdin);
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i,0);
}
for(int i=1;i<=n;i++){
if(!id[i]) Make_id(i,++sum);
}
for(int i=1;i<=n;i++){
cout<<i<<" belong to: "<<id[i]<<" scc"<<endl;
}
return 0;
}