Luogu P2661 信息传递

思路

显然,所有的边都是有向边。那么一个人能够得到自己的生日的条件便是这个人在一个环中,而且要求的是最小环。那么我们就可以用Tarjan算法求解。不会Tarjan的人可以去看看我另一篇随笔,专门讲的Tarjan我脚地窝写的海星。想看的话可以点这里。还有就是要注意环的大小必须要超过1。。。。

 

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>

const int maxn = 2e5+3;

using namespace std;

stack<int> S;
int n, x, f, u[maxn], v[maxn], first[maxn], next[maxn], cnt;
char c;
bool vis[maxn];
int low[maxn], dfn[maxn], Index, tot, ans = 2147483647;

inline int readInt() {
	x = 0, f = 1;
	c = getchar();
	while (c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while (c <= '9' && c >= '0') {
		x = x*10 + c-'0';
		c = getchar();
	}
	return x * f;
}

inline void Tarjan(int now) {
	low[now] = dfn[now] = ++Index;
	S.push(now);
	vis[now] = 1;
	int k = first[now];
	while (k != -1) {
		if(!dfn[v[k]]) {
			Tarjan(v[k]);
			low[now] = min(low[now], low[v[k]]);
		}
		else if(vis[v[k]] && dfn[v[k]]) {
			low[now] = min(low[now], dfn[v[k]]);
		}
		k = next[k];
	}
	int temp, num = 0;
	if(dfn[now] == low[now]) {
		while(!S.empty()) {
			temp = S.top();
			S.pop();
			num ++;
			vis[temp] = 0;
			if(temp == now) break;
		}
		if(num > 1) {
			ans = min(ans, num);
		}
	}
}

int main() {
	n = readInt();
	memset(first, -1, sizeof(first));
	for(int i=1; i<=n; i++) {
		u[i] = i, v[i] = readInt();
		next[i] = first[u[i]];
		first[u[i]] = i;
	}
	for(int i=1; i<=n; i++) {
		if(!dfn[i]) Tarjan(i);
	}
	printf("%d", ans);
}

  

posted @ 2018-07-19 10:23  Mystical-W  阅读(122)  评论(0编辑  收藏  举报