这道题是强联通分量的裸题。
首先我们都知道强连通分量就是 A 可以到达 B 且 B 也能到达 A 那么 A B 就是强连通分量,所以我们不妨分析一下,如果一个图里有一个环,那么可以确定的一点就是 这个环上所有的点之间都是强连通分量,所以我们在使用 tarjan 算法的时候,也就是在找一下图中的环,找到了环之后我们环上所有的点就都是相互之间的强连通分量了。
那么找环具体是什么样的过程呢,我们可以借助栈来实现,dfs思路
首先我们看一个点 A 和 A 相连的全部点,之后不断地 dfs ,并且把每个dfs的点加入栈中,而一旦我们发现下一个 dfs 的点是栈中的内容,那么很显然我们找到了一个环,这个栈里全部的点都相互之间为强连通分量,但是。。如果我们用朴素的思路去搞。。就会涉及到得遍历一下整个栈来寻找成环的那一部分,如果数据量过大很显然这有点蠢(我之前试了一下。。如果一个个去判断确实会容易爆炸)。
那么我们就需要采用一些智慧的策略来解决这个问题。
那就是加入 时间戳(对于某个节点搜索的次序编号),取作 dfn(x),之后再记录一下 x 出现的最早的栈中次序号low(x),有了这两个东西,我们只需要判断 dfn(x) == low(x) 就好了,low 相当于记录了这个环的起点,而 dfn 则是我们搜索每个节点第 n 次的编号,而当 dfn 没有初始值的时候,自然直接 +1 解决,而当 dfn 有值,的时候,代表我们找到了一个环的终点,之后要进行的就是把这个环部分退栈,记录就好了。
当然回到这道题,我们发现这里还需要字典序排序,所有我们构建一个结构体记录结果就好了。。。。
这个大犇的博客写的很好:https://www.cnblogs.com/shadowland/p/5872257.html
以下是本题的 AC 代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
inline int read()
{
char ch=getchar();int num=0;bool flag=false;
while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
return flag?-num:num;
}
struct node
{
int to,nxt;
}edge[maxn<<1];
int head[maxn],cnt;
inline void add(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
struct question
{
int val,s[5001];
bool operator < (const question x) const
{
return val==x.val?s[1]<x.s[1]:val>x.val;
}
}ques[2002];
stack<int>sta;
int n,m;
int dfn[maxn],low[maxn];
int tot,idx;
bool vis[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++idx;
sta.push(u);
vis[u]=true;
for(int i=head[u];~i;i=edge[i].nxt)
{
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]);
}
}
int t;
if(dfn[u]==low[u])
{
ques[++tot].val=0;
do
{
t=sta.top();sta.pop();
vis[t]=false;
ques[tot].val++;
ques[tot].s[ques[tot].val]=t;
}while(t!=u);
}
sort(ques[tot].s+1,ques[tot].s+1+ques[tot].val);
}
int main()
{
n=read();m=read();
memset(head,-1,sizeof(head));
int x,y,z;
for(int i=1;i<=m;++i)
{
x=read(),y=read(),z=read();
if(z==1)add(x,y);
if(z==2)add(x,y),add(y,x);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
sort(ques+1,ques+tot+1);
printf("%d\n",ques[1].val);
for(int i=1;i<=ques[1].val;++i)
{
printf("%d ",ques[1].s[i]);
}
return 0;
}