题解【洛谷P2341】 [HAOI2006]受欢迎的牛

题面

题解

\(Tarjan\)缩点后统计每个点的出度。

如果有多个点出度为\(0\),就直接输出\(0\),否则输出出度为\(0\)的强连通分量里的点数。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#define gI gi
#define itn int
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)

using namespace std;

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

int n, m, tot, head[100003], nxt[100003], ver[100003], vis[100003];
int x, y, dfn[100003], low[100003], sta[100003], sy[100003], ys[100003];
int num, cnt, sum, ans, kok;
int cd[100003];

inline void add(int u, int v)
{
	ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}

void Tarjan(int u)//Tarjan缩点
{
	dfn[u] = low[u] = ++num; sta[++cnt] = u; vis[u] = 1;
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = ver[i];
		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 y;
		++kok;
		do
		{
			y = sta[cnt--];
			vis[y] = 0;
			sy[y] = kok;
			++ys[kok];//统计强连通分量里点的个数
		} while (y != u);
	}
}

int main()
{
	//File("P2341");
	n = gi(), m = gi();
	for (int i = 1; i <= m; i+=1)
	{
		int u = gi(), v = gi();
		add(u, v);
	}
	for (int i = 1; i <= n; i+=1) if (!dfn[i]) Tarjan(i);
	for (int i = 1; i <= n; i+=1)
	{
		for (int j = head[i]; j; j = nxt[j])
		{
			int u = ver[j];
			if (sy[i] != sy[u])
			{
				++cd[sy[i]];//统计出度
			}
		}
	}
	int fl = 0;
	for (int i = 1; i <= kok; i+=1)
	{
		if (!cd[i])//出度为0
		{
			if (fl) {puts("0"); return 0;}//有多个出度为0的点,直接输出0
			fl = i;//记录答案所在的强连通分量的编号
		}
	}
	printf("%d\n", ys[fl]);//输出答案
	return 0;
}
posted @ 2019-08-07 11:49  csxsi  阅读(105)  评论(0编辑  收藏  举报