【洛谷】P2341 受欢迎的牛

题目地址:

https://www.luogu.com.cn/problem/P2341

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

输入格式:
第一行:两个用空格分开的整数: N N N M M M
接下来 M M M行:每行两个用空格分开的整数: A A A B B B,表示 A A A喜欢 B B B

输出格式:
一行单独一个整数,表示明星奶牛的数量。

数据范围:
对于 10 % 10\% 10%的数据, N ≤ 20 N\le20 N20 M ≤ 50 M\le50 M50
对于 30 % 30\% 30%的数据, N ≤ 1 0 3 N\le10^3 N103 M ≤ 2 × 1 0 4 M\le2\times 10^4 M2×104
对于 70 % 70\% 70%的数据, N ≤ 5 × 1 0 3 N\le5\times 10^3 N5×103 M ≤ 5 × 1 0 4 M\le5\times 10^4 M5×104
对于 100 % 100\% 100%的数据, 1 ≤ N ≤ 1 0 4 1\le N\le10^4 1N104 1 ≤ M ≤ 5 × 1 0 4 1\le M\le5\times 10^4 1M5×104

可以用Tarjan算法先对图缩点,这样就可以看缩点后的出度为 0 0 0的点有多少个,如果不唯一,则没有奶牛可以当明星。否则看一下出度为 0 0 0的点的size即可。思路参考https://blog.csdn.net/qq_46105170/article/details/116681582。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1e4 + 10, M = 5e4 + 10;
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, sz[N];
int dout[N];

void add(int a, int b) {
  e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void tarjan(int u) {
  dfn[u] = low[u] = ++timestamp;
  stk[top++] = u, in_stk[u] = true;
  for (int i = h[u]; ~i; i = ne[i]) {
    int v = e[i];
    if (!dfn[v]) {
      tarjan(v);
      low[u] = min(low[u], low[v]);
    } else if (in_stk[v]) low[u] = min(low[u], dfn[v]);
  }

  if (dfn[u] == low[u]) {
    scc_cnt++;
    int y;
    do {
      y = stk[--top];
      in_stk[y] = false;
      id[y] = scc_cnt;
      sz[scc_cnt]++;
    } while (y != u);
  }
}

int main() {
  memset(h, -1, sizeof h);
  scanf("%d%d", &n, &m);
  while (m--) {
    int a, b;
    scanf("%d%d", &a, &b);
    add(a, b);
  }
  
  for (int i = 1; i <= n; i++)
    if (!dfn[i]) tarjan(i);

  for (int i = 1; i <= n; i++)
    for (int j = h[i]; ~j; j = ne[j])
      if (id[i] != id[e[j]])
        dout[id[i]]++;
  
  int zero = 0, res;
  for (int i = 1; i <= scc_cnt; i++) {
    if (!dout[i]) {
      if (++zero > 1) {
        res = 0;
        break;
      }
      res = sz[i];
    }
  }

  printf("%d\n", res);
}

时间复杂度 O ( N + M ) O(N+M) O(N+M),空间 O ( N ) O(N) O(N)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值