既然爱慕关系可以传递,那么将互相可达的某几个点缩成一个点,就能简化原图了,
那么很自然想到tarjan求强连通分量
那么就只需找到可以被所有缩点遍历到的那个缩点
再输出它所含的点数就行了
先用tarjan将所有联通分量进行缩点,缩点后考虑出度为0的点的个数:
(1)个数大于1的时候,显然不存在受欢迎的牛!
(2)个数等于0的时候,假设有一头牛X是受欢迎的,那么它必定有喜欢的牛Y,而它又收到牛Y的欢迎,说明存在环,不是DAG图,矛盾!
(3)个数等于1的时候,用数学归纳法推一下,有这样一个结论:出度为0的那个点可以被其它所有点到达。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
const int maxm=5e4+5;
int n, m, a, b, cnt, num, top, col;
int head[maxm];
int s[maxm];
int st[maxm];
int co[maxm];
int de[maxm];
int dfn[maxm], low[maxm];
using namespace std;
struct cow {
int to;
int next;
} edge[maxm];
void add(int x, int y) {
cnt++;
edge[cnt].to = y;
edge[cnt].next = head[x];
head[x] = cnt;
}
void tarjan(int u) {
dfn[u] = low[u] = ++num;
st[++top] = u;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].to;
if (dfn[v] == 0) {
tarjan(v);
low[u] = min (low[u], low[v]);
} else if(co[v] == 0)
low[u] = min (low[u], low[v]);
}
if (low[u] == dfn[u]) {
co[u] = ++col;
++s[col];
while (st[top] != u) {
++s[col];
co[st[top]] = col;
--top;
}
--top;
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &a, &b);
add(b, a); //倒着存以最后统计出度而不是统计入度
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan (i);
for (int i = 1; i <=n; i++)
for (int j = head[i]; j; j = edge[j].next) {
int v = edge[j].to;
if (co[i] != co[v])
de[co[v]]++;
}
int ans = 0, u = 0;
for (int i = 1; i <= col; i++)
if(de[i] == 0) {
ans = s[i];
u++;
}
if(u == 1)
printf("%d\n", ans);
else
printf("0\n");
return 0;
}
void tarjan(int 当前点)
{
这个点的low=dfn=时间戳;
将这个点入栈;
标记这个点入栈;
枚举这个点连接的所有边
{
如果目标点没有被访问过
{
tarjan(目标点);
更新当前点的low;
}
如果目标点被访问过
{
更新当前点的low;
}
}
如果当前点的low==dfn
{
将这个点及栈以上的点出栈,标记成一个强连通分量;
ans++;
}
}