对于tarjan算法的理解写在tarjan学习笔记(poj2186&&bzoj1051受欢迎的牛)里面了
#include <cstdio>
#include <iostream>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 500000;
int low[MAXN],dfn[MAXN],nxt[MAXN],to[MAXN],tot = 1,head[MAXN],scc[MAXN],sz[MAXN];
int n,m,xbt[MAXN],rdu[MAXN],cdu[MAXN],ss[1000][1000];
bool vis[MAXN];
struct Edge
{
int f,t;
}e[MAXN << 1];
void build(int ff,int tt)
{
to[++tot] = tt;//我们建图只需确定该点的下一个点就行,有向边
nxt[tot] = head[ff];
head[ff] = tot;
}
stack <int> s;
int tim = 0,scccnt = 0;
void dfs(int u)
{
low[u] = dfn[u] = ++tim;
s.push(u);
int v ;
for(int i = head[u] ; i ; i = nxt[i])
{
v = to[i];
if(!dfn[v])//如果下一个点没有在栈中
{
dfs(v);//搜到下一个点
low[u] = min(low[v],low[u]);//那我们的low值就是该点的low值和下一个点的low值中小的那一个
}
else if(!scc[v])//如果本来就在栈中了,并且没有涂黑(就是不属于其他强连通分量)
{
low[u] = min(low[u],dfn[v]);//low值的更新是取当前点的low值与搜到的点的dfn值中小的那一个
}
}
if(low[u] == dfn[u])
{
int x ;
scccnt ++;//数量++
while(!s.empty())//出栈操作
{
x = s.top();
s.pop();
scc[x] = scccnt;//这些点都属于一个强连通分量
sz[scccnt]++;//记录这个强连通分量的个数
if(u == x)
break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i ++)
{
scanf("%d%d",&e[i].f,&e[i].t);
build(e[i].f,e[i].t);
}
for(int i = 1; i <= n; i ++)
if(!dfn[i])//刚开始所有点都是白点,也就是0,在搜的过程中变灰点,出栈后涂黑
dfs(i);//从没有搜过的开始搜
int ans = 0,q=0;
for(int i = 1; i <= m; i ++)
{
if(scc[e[i].f] != scc[e[i].t] )//如果这个点与它所连向的点不在一个强连通分量
xbt[scc[e[i].f]] ++;//说明这个点所在的强连通分量不符合条件
}
for(int i =1; i <= scccnt; i ++)//scccnt是强连通分量的个数
{
if(sz[i] >1)
{
q++;//记录一下数量
}
}
int smg = 0;
for(int i = 1; i <= scccnt; i ++)
{
if(!xbt[i]&&sz[i] >1)//如果这个点所在的强连通分量符合条件 是个环
{
smg ++;//记录一下环的数量
ans = i;//这个强连通分量的编号赋给ans
}
}
cout <<q <<endl;
if(smg > 1||ans == 0)//如果环的数量大于1 或者没有环
{
puts("-1");
}
else//有且只有一个环
{
for(int i = 1; i <= n; i ++)
if(scc[i] == ans)//如果这个点属于这个强连通分量
cout <<i<<" ";
}
return 0;
}