题目链接:https://www.luogu.com.cn/problem/P1726
tarjan的一道模板题,t=1连一条单向边,t=2连一条双向边。tarjan跑一遍,一个绝对连通区域就是一个强连通分量。tarjan中每次找到一个强连通分量,记录这个强连通分量有多少个点。然后找到强连通分量最大的那个,从前往后找,就保证了字典序最小的优先,最后输出属于那个连通块的点即可。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+5;
const int maxm=1e5+5;
int head[maxn];
struct node
{
int to,next;
}edge[maxm];
int cnt;
void add(int x,int y)
{
edge[++cnt].next=head[x];
edge[cnt].to=y;
head[x]=cnt;
}
int dfn_number,top,color;
int dfn[maxn],low[maxn],col[maxn],stc[maxn],col_num[maxn];
bool vis[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++dfn_number;
stc[++top]=u;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int len=1;
vis[u]=false;
col[u]=++color;
while(stc[top]!=u)
{
vis[stc[top]]=false;
col[stc[top--]]=color;
len++;
}
top--;
col_num[color]=len;
}
}
int n,m;
int opt,x,y;
int main()
{
scanf("%d %d",&n,&m);
while(m--)
{
scanf("%d %d %d",&x,&y,&opt);
if(opt==1)
{
add(x,y);
}
else
{
add(x,y);
add(y,x);
}
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
int ma=0,t;
for(int i=1;i<=n;i++)
{
if(col_num[col[i]]>ma)
{
ma=col_num[col[i]];
t=col[i];
}
//cout<<col[i]<<endl;
}
printf("%d\n",ma);
for(int i=1;i<=n;i++)
{
if(col[i]==t)
printf("%d ",i);
}
return 0;
}