• 洛谷P2341 [HAOI2006]受欢迎的牛 (Tarjan,SCC缩点)


    P2341 [HAOI2006]受欢迎的牛|【模板】强连通分量

    https://www.luogu.org/problem/P2341

    题目描述

    每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

    牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

    欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

    算出有多少头奶牛可以当明星。

    输入格式

     第一行:两个用空格分开的整数:N和M

     第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

    输出格式

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

    输入输出样例

    输入 #1复制

    输出 #1复制

    说明/提示

    只有 3 号奶牛可以做明星

    【数据范围】

    10%的数据N<=20, M<=50

    30%的数据N<=1000,M<=20000

    70%的数据N<=5000,M<=50000

    100%的数据N<=10000,M<=50000

    思路:

    使用Tarjan算法把SCC缩成点后,在DAG中判断是否有一个节点,使所有其他节点都可以到达它。

    判断方法:

    DAG中有且仅有一个节点出度为0,那么这个点就满足所有其他节点都可以到达它。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define sz(a) int(a.size())
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define du2(a,b) scanf("%d %d",&(a),&(b))
    #define du1(a) scanf("%d",&(a));
    using namespace std;
    typedef long long ll;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
    void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    
    inline void getInt(int *p);
    const int maxn = 100010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    
    int From[maxn], Laxt[maxn], To[maxn << 2], Next[maxn << 2], cnt;
    int low[maxn], dfn[maxn], times, q[maxn], head, scc_cnt, scc[maxn];
    vector<int>G[maxn];
    int dis[maxn], S, T, ans;
    int num[maxn];
    void add(int u, int v)
    {
        Next[++cnt] = Laxt[u]; From[cnt] = u;
        Laxt[u] = cnt; To[cnt] = v;
    }
    void tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++times;
        q[++head] = u;
        for (int i = Laxt[u]; i; i = Next[i]) {
    //        if (To[i] == fa) { continue; }
            if (!dfn[To[i]]) {
                tarjan(To[i], u);
                low[u] = min(low[u], low[To[i]]);
            } else { low[u] = min(low[u], dfn[To[i]]); }
        }
        if (low[u] == dfn[u]) {
            scc_cnt++; 
            while (true) {
                int x = q[head--];
                scc[x] = scc_cnt;
                num[scc_cnt]++;
                if (x == u) { break; }
            }
        }
    }
    void init()
    {
        memset(Laxt, 0, sizeof(Laxt));
        cnt = 0;
    }
    int main()
    {
        init();
        int N, M, u, v, i, j;
        scanf("%d%d", &N, &M);
        for (i = 1; i <= M; i++) {
            scanf("%d%d", &u, &v);
            add(u, v);
        }
        repd(i, 1, N) {
            if (!dfn[i]) {
                tarjan(i, 0);
            }
        }
        for (i = 1; i <= N; i++) {
            for (j = Laxt[i]; j; j = Next[j]) {
                if (scc[i] != scc[To[j]]) {
                    G[scc[i]].push_back(scc[To[j]]);
                }
            }
        }
        int id;
        int out = 0;
        repd(i, 1, scc_cnt) {
            if (sz(G[i]) == 0) {
                out++;
                id = i;
            }
        }
        if (out == 1) {
            printf("%d
    ", num[id] );
        } else {
            printf("0
    ");
        }
    
        return 0;
    }
    inline void getInt(int *p)
    {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        } else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    
    
    
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    POJ 2996 Help Me with the Game (模拟)
    PCL系列——怎样逐渐地配准一对点云
    sublime text3同时编辑多行
    博客搬家
    将博客搬至CSDN
    centos7用xshell可以连接, xftp连接失败!(墙裂推荐)
    重启ssh服务出现Redirecting to /bin/systemctl restart sshd.service
    重装wordpress
    ubuntu 16.04 启用root用户方法
    Ubuntu创建新用户并增加管理员权限(授权有问题)
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/11585285.html
Copyright © 2020-2023  润新知