1513:【 例 1】受欢迎的牛

1513:【 例 1】受欢迎的牛

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 808 通过数: 428
【题目描述】
原题来自:USACO 2003 Fall

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

【输入】
第一行两个数 N,M;

接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)。

【输出】
输出被除自己之外的所有牛认为是受欢迎的牛的数量。

【输入样例】
3 3
1 2
2 1
2 3
【输出样例】
1
【提示】
样例说明

只有第三头牛被除自己之外的所有牛认为是受欢迎的。

数据范围:

对于全部数据,1≤N≤104,1≤M≤5×104。

思路:缩点,是否只有一个出度为0的缩点集合。

#include <bits/stdc++.h>

using namespace std;
const int N=5e4+5;
int n,m,dfn[N],vis[N],low[N],t=0,num=0,b[N],cnt[N];
int x[N],y[N],out[N];
vector<int> a[N];
stack<int> s;

void dfs(int x)
{
    dfn[x]=low[x]=++t;
    s.push(x);
    vis[x]=1;
    for(int i=0;i<a[x].size();i++)
    {
        int y=a[x][i];
        if(!dfn[y])
        {
            dfs(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])
            low[x]=min(low[x],low[y]);
    }
    if(low[x]==dfn[x])
    {
        num++;
        while(s.top()!=x)
        {
            b[s.top()]=num;//编号
            cnt[num]++;
            vis[s.top()]=0;
            s.pop();
        }
        b[x]=num;
        cnt[num]++;
        vis[x]=0;
        s.pop();
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    //cin >> n >> m;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        //cin >> x[i] >> y[i];
        a[x[i]].push_back(y[i]);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            dfs(i);
    for(int i=0;i<m;i++)//新建图,缩点
    {
        int x0=b[x[i]],y0=b[y[i]];
        if(x0!=y0)
            out[x0]++;
    }
    int res=0,x=0;
    for(int i=1;i<=num;i++)
    {
        if(out[i]==0)
        {
            x=i;
            res++;
        }
        if(res>1)
        {
            printf("0\n");
            return 0;
        }
    }
    printf("%d\n",cnt[x]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值