P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G —— Tarjan缩点

[USACO03FALL / HAOI2006] 受欢迎的牛 G

题目背景

本题测试数据已修复。

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 \(A\) 喜欢 \(B\)\(B\) 喜欢 \(C\),那么 \(A\) 也喜欢 \(C\)。牛栏里共有 \(N\) 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。

输入格式

第一行:两个用空格分开的整数:\(N\)\(M\)

接下来 \(M\) 行:每行两个用空格分开的整数:\(A\)\(B\),表示 \(A\) 喜欢 \(B\)

输出格式

一行单独一个整数,表示明星奶牛的数量。

样例 #1

样例输入 #1

3 3
1 2
2 1
2 3

样例输出 #1

1

提示

只有 \(3\) 号奶牛可以做明星。

【数据范围】

对于 \(10\%\) 的数据,\(N\le20\)\(M\le50\)

对于 \(30\%\) 的数据,\(N\le10^3\)\(M\le2\times 10^4\)

对于 \(70\%\) 的数据,\(N\le5\times 10^3\)\(M\le5\times 10^4\)

对于 \(100\%\) 的数据,\(1\le N\le10^4\)\(1\le M\le5\times 10^4\)

分析

先跑Tarjan求出所有SCC。

当新图上有且仅有一个出度为零的点 $ id $ 时有 $ ans=siz[id] $ 。

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+100,M=1e5+100;
int n,m;
int dfn[N],low[N],tot,dd;
int sta[N],top,id,scc[N],siz[N];
int deg1[N],deg2[N];
bool inc[N];
vector<int>g[N],h[N];
void go(int u)
{
    sta[++top]=u;
    inc[u]=1;
    low[u]=dfn[u]=++tot;
    for(int i=0;i<deg1[u];++i)
    {
        int v=g[u][i];
        if(!dfn[v])
        {
            go(v);
            low[u]=min(low[u],low[v]);
        }
        else if(inc[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ++id;
        while(sta[top]!=u)
        {
            scc[sta[top]]=id;
            ++siz[id];
            inc[sta[top]]=0;
            --top;
        }
        scc[u]=id;
        ++siz[id];
        inc[u]=0;
        --top;
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        ++deg1[x];
    }
    for(int i=1;i<=n;++i)
        if(!dfn[i])
            go(i);
    for(int i=1;i<=n;++i)
    {
        for(int j=0;j<deg1[i];++j)
        {
            int v=g[i][j];
            if(scc[v]!=scc[i])
                h[scc[i]].push_back(scc[v]);
        }
    }

    for(int i=1;i<=id;++i)
        deg2[i]=unique(h[i].begin(),h[i].end())-h[i].begin();
    int tot=0,num=0;
    for(int i=1;i<=id;++i)
    {
        if(deg2[i]==0)
        {
            ++tot;
            num=siz[i];
        }
    }
    if(tot!=1){cout<<0;}
    else cout<<num;
    return 0;
}
posted @ 2024-11-29 11:35  Glowingfire  阅读(3)  评论(0编辑  收藏  举报