强连通裸题,跑tarjan找最大的环,每次记录第一次找到该点的时间(dfn)与该点不通过父亲能到达的最早的祖先(low),第一次找到时将该点入栈,对于该点没搜过的子节点,我们用子节点的low来更新该点的low,对于搜过的且还在栈中子节点,用它的dfn来更新我的low。
如果有一个节点的dfn==low,则说明该节点与该节点在栈中以上的所有节点构成了一个强联通分量,全部出栈并记录信息。
Code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
struct node{int y,next;}a[50010];
int n,m,len=0,top=0,id=0,tot;
int first[5010],dfn[5010],low[5010],belong[5010],size[5010],sta[5010];
bool vis[5010];
//dfn搜到的时间 low不通过父亲能去到的最早的祖先 sta模拟栈
//belong每个点属于哪个连通子图 size连通子图的大小 vis是否在栈中
void ins(int x,int y){a[++len]=(node){y,first[x]};first[x]=len;}
void dfs(int x)
{
dfn[x]=low[x]=++id;
sta[++top]=x;
vis[x]=true;
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(dfn[y]==-1)
{
dfs(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
tot++;
int i;
do
{
i=sta[top--];
++size[belong[i]=tot];
vis[i]=false;
}while(i!=x);
}
}
void tarjan()
{
memset(dfn,-1,sizeof(dfn));
memset(size,0,sizeof(size));
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++)
if(dfn[i]==-1) dfs(i);
}
void print()
{
int maxx=size[belong[1]];
for(int i=2;i<=n;i++)
if(size[maxx]<size[belong[i]]) maxx=belong[i];
printf("%d\n",size[maxx]);
for(int i=1;i<=n;i++)
if(belong[i]==maxx) printf("%d ",i);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,t;
scanf("%d %d %d",&x,&y,&t);
ins(x,y);
if(t==2) ins(y,x);
}
tarjan();
print();
}