lzg_070506 @ 2023-07-14 08:34:33
写法与常规Tarjan略有不同
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
int e[100010],ne[100010],h[10010],idx;
int dfn[10010],low[10010],ti;
int stk[10010],top;
bool st[10010];
struct SCC{//结构体方便排序
int x,id;
bool operator< (const SCC &ID)const{
return id<ID.id;
}
}I[10010];
void add(int a,int b){
e[idx]=b;ne[idx]=h[a];h[a]=idx;idx++;
}
void tarjan(int u){
ti++;
dfn[u]=low[u]=ti;
top++;
stk[top]=u;
st[u]=true;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!dfn[j]){
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(st[j]) low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u]){
int y=-1;
ans++;
int c=top,mi=u;
while(y!=u){//寻找该连通分量中编号最小的点
y=stk[c--];
mi=min(mi,y);
}
y=-1;
while(true){
y=stk[top];top--;
st[y]=false;
I[y].id=mi;用分量内编号最小点编号标记
if(y==u) break;
}
}
}
int main(){
memset(h,-1,sizeof(h));
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++){
I[i].x=i;
if(!dfn[i]){
tarjan(i);
}
}
sort(I+1,I+n+1);
cout<<ans<<endl;
int ii=I[1].id;
for(int i=1;i<=n;i++){
if(ii!=I[i].id){
ii=I[i].id;
cout<<endl;
}
cout<<I[i].x<<" ";
}
return 0;
}