luogu P2661 信息传递 强连通分量求最小环

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200000+10, M = 200000+10;
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
//          栈顶
int stk[N], top;
bool in_stk[N];
//属于哪个连通分量
int id[N];
//当前有多少强连通分量
int scc_cnt;
//每个强连通分量中点的数量
int Size[N];
//每个连通分量的出度
int dout[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u)
{
	//先都等于时间戳
	dfn[u] = low[u] = ++ timestamp;
	//把当前点加到栈当中去
	//栈当中存的值,不单单是当前路径上的值,还可能存其他边上的点
	//存的点,都不是它所在强连通分量的最高点
	//都是,当前,还没有搜完的遍历完的,强连通分量的所有点
	stk[ ++ top] = u;
	//记录是否在栈当中
	in_stk[u] = true;
	//遍历u的所有临点
	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 (in_stk[j])
			//取最小
			low[u] = min(low[u], dfn[j]);
	}
	//遍历完u之后,发现u能到的最前面的点就是自己了
	if (dfn[u] == low[u])
	{
		//那就说明,u肯定是所在强连通分量的最高点
		//所有强连通分量个数++
		++ scc_cnt;
		int y;
		do
		{
			//先取出栈顶元素
			y = stk[top -- ];
			//表示出栈
			in_stk[y] = false;
			//标记当前点属于哪个强连通分量
			id[y] = scc_cnt;
			//
			Size[scc_cnt] ++ ;
			//y==u时,表示所在强连通分量处理完了
		}
		while (y != u);
	}
}
int main()
{
	cin>>n;
	memset(h, -1, sizeof h);
	for(int i=1; i<=n; i++)
	{
		int x;
		cin>>x;
		add(i,x);
	}
	//建新图
	for (int i = 1; i <= n; i ++ )
		if (!dfn[i])
			tarjan(i);
	int ans=0x3f3f3f3f;
	for(int i=1; i<=scc_cnt;i++)
	{
		int j=Size[i];
		if(j>1)
			ans=min(ans,j);
	}
	cout<<ans<<endl;
	return 0;
}

posted @ 2020-05-12 18:53  晴屿  阅读(123)  评论(0编辑  收藏  举报