受欢迎的牛——Tarjan

题目描述
题目来源:河南省选2006
链接: POJ2186 http://poj.org/problem?id=2186 bzoj1051 http://www.lydsy.com/JudgeOnline/problem.php?id=1051

每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛,给你 M 对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
输入格式:
第一行两个数 N,M 。
接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)
输出格式:
输出一个整数,即有多少头牛被所有的牛认为是受欢迎的。如果没有满足这种条件的情况,输出“0”。
样例输入:
3 3
1 2
2 1
2 3
样例输出:
1
样例说明:
只有牛 3 是受到所有牛欢迎的。
数据范围:
10% 的数据:N≤20;M≤50
30% 的数据:N≤1000;M≤20000
70% 的数据:N≤5000;M≤50000
100% 的数据:N≤10000;M≤50000
题目分析
Tarjan模板题。只需缩点后记录出度,当且仅当只有一个出度为0的点(实际可能是一个强连通分量),存在最受欢迎的牛,个数为强连通分量的大小。否则,没有最受欢迎的牛,输出0。
注:不懂Tarjan的可以看我的讲解:http://blog.csdn.net/qianguch/article/details/54710272
附代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<iomanip>
#include<cctype>
#include<set>
#include<map>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

const int maxn=1e4+10;
const int maxm=5e4+10;
int top,tot,n,m,times,cnt,dfn[maxn],low[maxn];
int nxt[maxm],to[maxm],first[maxn],stack[maxn];
int pd[maxn],num[maxn],x,y,du[maxn],sum,bh;
bool  vis[maxn],insta[maxn];

void create(int x,int y)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
}

void dfs(int u)
{
    times++;
    dfn[u]=times;
    low[u]=times;
    vis[u]=true;
    insta[u]=true;
    stack[top++]=u;
    for(int e=first[u];e;e=nxt[e])
    {
        if(vis[to[e]]==false)
        {
            dfs(to[e]);
            low[u]=min(low[u],low[to[e]]);
        }
        else
            if(insta[to[e]]==true)
                low[u]=min(low[u],dfn[to[e]]);
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        while(top>=1&&stack[top]!=u)
        {
            top--;
            insta[stack[top]]=false;
            pd[stack[top]]=cnt;
            num[cnt]++;//记录每个强连通分量的大小
        }
    }
}

int main()
{
    //freopen("lx.in","r",stdin);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        create(x,y);
    }
    for(int i=1;i<=n;i++)
        if(vis[i]==false)
            dfs(i);

    for(int i=1;i<=n;i++)
        for(int e=first[i];e;e=nxt[e])
            if(pd[i]!=pd[to[e]])
                du[pd[i]]++;//计算出度

    for(int i=1;i<=cnt;i++)
    {
        if(du[i]==0)//看有多少个出度为0
        {
            sum++;
            bh=i;
        }
    }
    if(sum==1)
        printf("%d",num[bh]);
    else
        printf("0");

    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值