PKU2186 Popular Cows 受欢迎的牛

Description

每一头牛的愿望就是变成一头最受欢迎的牛。现在有N(N<=10000)头牛,给你M(M<=50000)对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

Input

第一行两个数N,M。
接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复)
N<=10000,M<=50000

Output

一个数,即有多少头牛被所有的牛认为是受欢迎的

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1




这是一道关于强连通的题,首先建好强连通分量;
再统计每个强连通的出度,如果有一个强连通出度为0;
则,这个强连通没有可以到达其它强连通的有向边;
也同时说明,这个强连通内的牛只互相喜欢,没有喜欢其它的牛;
但是不能有多个强连通分量出度为0;要保证它是被所有的牛喜欢的;
这样就算出,唯一出度为0的强连通分量里有多少头牛就可以了;

附上代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
ll n,m,ans,sum,s,top,num;
ll head[100001],low[50001],dfn[50001];
ll f[50001],aa[50001],cd[50001],anss[50001];
struct sbbbbbbb
{
    ll to,stb;//to为这条边到达的点,stb为上条边的编号 
}a[100001];
inline void insert(ll x,ll y)
{
    s++;
    a[s].to=y;
    a[s].stb=head[x];
    head[x]=s;
}//前向星连边 
inline void dfs(ll x)
{
    num++;
    dfn[x]=low[x]=num;
    top++;
    aa[top]=x;
    for(ll i=head[x];i;i=a[i].stb)//基础的遍历求low,和dfn的值 
    {
        ll xx=a[i].to;
        if(!dfn[xx])
        {
            dfs(xx);
            low[x]=min(low[x],low[xx]);
        }
        else if(!f[xx])
            low[x]=min(low[x],dfn[xx]);
    }
    if(low[x]==dfn[x])//如果可以通过返祖边回答父节点,
                      //那么这些点都属于一个强连通分量 
    {
        sum++;
        f[x]=sum;//标记属于哪个强连通 
        while(aa[top]!=x)
        {
            f[aa[top]]=sum;//标记属于哪个强连通 
            anss[sum]++;//计算这个强连通分量里有多少个点 
            top--;
        }
        anss[sum]++;
        top--;
    }
}
int main()
{
    n=read();m=read();
    for(ll i=1;i<=m;i++)
    {
        ll x,y;
        x=read();y=read();
        insert(x,y);//连边 
    }
    for(ll i=1;i<=n;i++)
    if(!dfn[i])
        dfs(i);
    for(ll i=1;i<=n;i++)
    for(ll j=head[i];j;j=a[j].stb)
    if(f[i]!=f[a[j].to])//如果他们不是在一个强连通分量,
                       //并且可以由f[i]到达f[a[j].to] 
        cd[f[i]]++;//统计f[i]这个强连通的出度 
    for(ll i=1;i<=sum;i++)
    if(!cd[i])//枚举,看是否有出度为0的强连通 
    {
        if(ans==0)
            ans=anss[i];
        else//有多个出度为0,则没有答案 
        {
            printf("0");
            return 0;
        }
    }
    printf("%lld",ans);
}

下面纯属搞笑,可以不理会:

黄牛模板:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
ll n,m,ans,sum,s,top,num;
ll head[100001],low[50001],dfn[50001];
ll f[50001],aa[50001],cd[50001],anss[50001];
struct sbbbbbbb
{
    ll to,stb; 
}a[100001];
inline void insert(ll x,ll y)
{
    s++;
    a[s].to=y;
    a[s].stb=head[x];
    head[x]=s;
} 
inline void dfs(ll x)
{
    num++;
    dfn[x]=low[x]=num;
    top++;
    aa[top]=x;
    for(ll i=head[x];i;i=a[i].stb) 
    {
        ll xx=a[i].to;
        if(!dfn[xx])
        {
            dfs(xx);
            low[x]=min(low[x],low[xx]);
        }
        else if(!f[xx])
            low[x]=min(low[x],dfn[xx]);
    }
    if(low[x]==dfn[x])  
    {
        sum++;
        f[x]=sum; 
        while(aa[top]!=x)
        {
            f[aa[top]]=sum; 
            anss[sum]++; 
            top--;
        }
        anss[sum]++;
        top--;
    }
}
int main()
{
    n=read();m=read();
    for(ll i=1;i<=m;i++)
    {
        ll x,y;
        x=read();y=read();
        insert(x,y); 
    }//输入牛的编号 
    for(ll i=1;i<=n;i++)
    if(!dfn[i])
        dfs(i);//找谁是最受欢迎的牛 
    printf("最 受 欢 迎 的 牛 是 黄 牛
我 是 黄 牛 沃 泰 牛");
}

只要将黄牛模板交到入门oj的4916

就会AC

原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/12936800.html