zoukankan      html  css  js  c++  java
  • 洛谷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
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    Markdown引用图片,且不使用网上链接的解决方法
    测试
    sudo用户权限添加问题
    windows安装ipython
    ansible基本操作
    mysql用户权限操作
    解决windows7系统的快捷方式无法添加到任务栏
    linux下查看磁盘分区的文件系统格式
    mail客户端POP和IMAP协议
    linux设置history历史记录
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11360662.html
Copyright © 2011-2022 走看看