• 洛谷P2341 受欢迎的牛(tarjan强连通分量模板)


    题目链接:洛谷P2341 受欢迎的牛

    题意

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


    思路

    由题可得,受欢迎的奶牛只有可能是图中唯一的出度为零的强连通子图中的所有奶牛,所以若出现两个以上出度为0的强连通子图则不存在明星奶牛,因为那若干个出度为零的子图的爱慕无法传递出去。那唯一的子图能受到其他子图的爱慕同时可以在子图内相互传递,所以该子图中的所有奶牛都是明星。

    时间复杂度$O(n+m)$

    代码实现

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <stack>
    using std::min;
    using std::stack;
    const int N = 10010, M = 50010;
    struct Edge
    {
        int to, nex;
    } edge[M];
    int num_e;
    int head[N], du[N];
    // scc: scc[u]表示u所在的强联通子图编号; sz[i]表示第i个强联通子图规模; idx: dfs时间戳; tot: 统计强联通子图个数;
    int dfn[N], low[N], scc[N], sz[N], idx, tot;
    bool insta[N];
    int sta[N], top;
    void init() {
        num_e = 0, top = 0, idx = 0, tot = 0;
        memset(head, 0, sizeof(head));
        memset(du, 0, sizeof(du));
        memset(insta, 0, sizeof(insta));
        memset(scc, 0, sizeof(scc));
        memset(dfn, 0, sizeof(dfn));
    }
    void add_edge(int x, int y) {
        edge[++num_e].to = y;
        edge[num_e].nex = head[x];
        head[x] = num_e;
    }
    void tarjan(int u) {  // tarjan求强联通分量模板
        dfn[u] = low[u] = ++idx;
        sta[++top] = u;
        insta[u] = true;
        for (int i = head[u]; i; i = edge[i].nex) {
            int v = edge[i].to;
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (insta[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            ++tot;
            do {
                scc[sta[top]] = tot;
                sz[tot]++;
                insta[sta[top]] = false;
            } while (sta[top--] != u);
        }
    }
    
    int main() {
        int n, m;
        while (~scanf("%d %d", &n, &m)) {
            init();
            for (int i = 0, u, v; i < m; i++) {
                scanf("%d %d", &u, &v);
                add_edge(u, v);
            }
            for (int i = 1; i <= n; i++) {
                if (!dfn[i]) tarjan(i);
            }
            for (int u = 1; u <= n; u++) {
                for (int i = head[u]; i; i = edge[i].nex) {
                    int v = edge[i].to;
                    if (scc[u] != scc[v]) du[scc[u]]++;
                }
            }
            int ans = 0;
            for (int i = 1; i <= tot; i++) {
                if (!du[i]) {
                    if (ans) {
                        ans = 0;
                        break;
                    }
                    ans = i;
                }
            }
            printf("%d
    ", ans ? sz[ans] : 0);
        }
        return 0;
    }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    maven项目自动创建src/main/resources等四个资源文件夹
    @Async异步注解与SpringBoot结合使用
    java.util.concurrent包下并发锁的特点与适用场景
    java.util.concurrent包下集合类的特点与适用场景
    springMvc接收ajax数组参数,以及jquery复选框选中、反选、全选、全不选
    MySql 的SQL执行计划查看,判断是否走索引
    windows server系统查看tomcat版本
    物化视图SQL
    element-ui的不稳定性
    ActiveMQ-5.15.2下载和启动(windows)
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11360662.html
Copyright © 2020-2023  润新知