P2341 [HAOI2006]受欢迎的牛 (tarjan缩点+出度)

博客围绕奶牛明星问题展开,每头奶牛都有成为明星的梦想,被所有奶牛喜欢的就是明星,且喜欢关系可传递。给定牛栏中奶牛数量及爱慕关系,解题思路是用tarjan缩点后找出度为0的点,若有1个则是明星,超1个则无明星。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

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

思路:

tarjan缩点后找出度为0的点,若有1个,则是明星,超过1个则没有明星。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e4 + 10;
int n, m, h[N], cnt, d[N], x[N], y[N];
int dfn[N], low[N], ins[N], scc[N], inde;
stack<int> s;
struct node {
    int v, net;
} no[N];
void add(int u, int v) {
    no[cnt].v = v;
    no[cnt].net = h[u];
    h[u] = cnt++;
}
void tarjan(int u) {
    dfn[u] = low[u] = ++inde;
    s.push(u);
    ins[u] = 1;
    for(int i = h[u]; ~i; i = no[i].net) {
        int v = no[i].v;
        if(!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if(ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]) {
        while(s.top() != u) {
            int v = s.top();
            ins[v] = 0, scc[v] = u;
            s.pop();
        }
        ins[u] = 0, scc[u] = u;
        s.pop();
    }
}
int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m;
    for(int i = 0; i < m; i++) {
        cin >> x[i] >> y[i];
        add(x[i], y[i]);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i])
            tarjan(i);
    int ans = 0, ru = 0, root = -1;
    for(int i = 1; i <= n; i++)
        for(int j = h[i]; ~j; j = no[j].net) {
            int v = no[j].v;
            if(scc[i] != scc[v]) {
                d[scc[i]]++;//统计出度
            }
        }
    for(int i = 1; i <= n; i++)
        if(d[scc[i]] == 0 && root != scc[i])//防止同一个强连通分量的重复统计
            ru++, root = scc[i];//记录出度为0的个数
    if(ru > 1) {
        cout << 0;
        return 0;
    }
    for(int i = 1; i <= n; i++)
        if(scc[i] == root)//计算强连通分量有多少牛
            ans++;
    cout << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值