[复习][poj2186]Tarjan Popular Cows

如果对tarjan算法有所遗忘,请参见千古的博客

题目背景
POJ2186

HAOI2006 DAY1 T3

题目描述
每一头牛的愿望就是变成一头最受欢迎的牛。现在有 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模板

代码:

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

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

const int maxn=10010;
const int maxm=50010;
int tot=1,n,m,x,y,sum,bh,dep,top,cnt,ans;//tot=1要养成习惯,因为在有向图tarjan中可能会用到异或求对边的情况
int first[maxn],nxt[maxm],to[maxm];
int zhan[maxn],dfn[maxn],low[maxn],qlt[maxn];
bool bj[maxn],ruzhan[maxn];

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

void tarjan(int u)
{
    dfn[u]=++dep;//不要用index,linux环境下会死的
    low[u]=dep;
    ruzhan[u]=true;
    zhan[top]=u;
    top++;

    for(int p=first[u];p;p=nxt[p])
    {
        int v=to[p];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
        {
            if(ruzhan[v])//只有栈内横叉边才能更新
                low[u]=min(low[u],dfn[v]);
        }
    }

    if(dfn[u]==low[u])
    {
        cnt++;
        while(zhan[top]!=u)
        {
            top--;
            qlt[zhan[top]]=cnt;
            ruzhan[zhan[top]]=false;
        }
    }
}

int main()
{
    freopen("cows.in","r",stdin);
    freopen("cows.out","w",stdout);

    n=getint(),m=getint();
    for(int i=1;i<=m;++i)
    {
        x=getint(),y=getint();
        addedge(x,y);
    }

    for(int i=1;i<=n;++i)
        if(!dfn[i])
            tarjan(i);

    for(int i=1;i<=n;++i)
        for(int p=first[i];p;p=nxt[p])
        {
            int v=to[p];
            if(qlt[v]!=qlt[i])
                bj[qlt[i]]=1;//这个连通块有出度
        }

    for(int i=1;i<=cnt;++i)
        if(bj[i]==0)
        {
            sum++;
            bh=i;
        }

    if(sum==1)//只能有一个出度为0的连通块,不然就成了有两批牛互相不认为对方受欢迎,也就没有一只满足受所有牛欢迎了
    {
        for(int i=1;i<=n;++i)
            if(qlt[i]==bh)
                ans++;

        cout<<ans<<'\n';
    }
    else
        cout<<0<<'\n';
    return 0;
} 

本题结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值