P2341 [HAOI2006]受欢迎的牛

题目描述

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

输入格式

第一行:两个用空格分开的整数:NN 和 MM。

接下来 MM 行:每行两个用空格分开的整数:AA 和 BB,表示 AA 喜欢 BB。

输出格式

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


题解:
Tarjan缩点,然后判断是否有且仅有一个点的出度为0,因为如果有两个或以上的点出度为0,这些奶牛是不可能相互喜欢的,那么答案就是唯一的出度为0的那个点包含的强连通分量的点的个数


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
const int MAXN = 1e4+50;
const int MAXM = 5e4+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int dfn[MAXN],low[MAXN],num[MAXN],bel[MAXN],instack[MAXN],st[MAXN];
int n,m,k,tot,cnt,top,out[MAXN];
int head[MAXN],to[MAXM],nxt[MAXM];
inline void add(int u,int v){ to[++tot]=v; nxt[tot]=head[u]; head[u]=tot; }
void tarjan(int u){
    dfn[u]=low[u]=++cnt; st[++top]=u; instack[u]=1;
    for(int i=head[u];i;i=nxt[i]){
        if(!dfn[to[i]]) tarjan(to[i]),low[u]=min(low[u],low[to[i]]);
        else if(instack[to[i]]) low[u]=min(low[u],dfn[to[i]]);
    }
    if(dfn[u]==low[u]){
        ++k; int v;
        do{
            v=st[top--]; instack[v]=0; bel[v]=k; num[k]++;
        }while(u!=v);
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
    scanf("%d%d",&n,&m); int res=0;
    for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v);
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=nxt[j])
            if(bel[i]!=bel[to[j]])
                out[bel[i]]++;
    for(int i=1;i<=k;i++){
        if(!out[i]){
            if(res){ puts("0");return 0; }
            res = i;
        }
    }
    printf("%d\n",num[res]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值