zoukankan      html  css  js  c++  java
  • 【BZOJ 1051】[HAOI2006]受欢迎的牛

    1051: [HAOI2006]受欢迎的牛

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3375  Solved: 1771
    [Submit][Status][Discuss]

    Description

    每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

    Input

    第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)

    Output

    一个数,即有多少头牛被所有的牛认为是受欢迎的。

    Sample Input

    3 3
    1 2
    2 1
    2 3

    Sample Output

    1

    HINT

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

    Source


    ANALYSIS


    我的思路很简单很暴力,先把环缩点变成DAG,然后按拓扑序递推支持人数。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 10005;
    const int MAXM = 50005;
    
    struct Edge
    {
        int from, to, next;
        
        Edge() {
        }
        
        Edge(int u, int v) : from(u), to(v) {
        }
        
    }edges[MAXM], edt[MAXM];
    
    int n, m;
    int first[MAXN], ft[MAXN], sccno[MAXN], dg[MAXN], bkn[MAXN], scc_cnt;
    int topsort[MAXN], f[MAXN], toplen;
    bool vis[MAXN];
    
    void dfs1(int u)
    {
        if (!vis[u]) return;
        vis[u] = false;
        for (int i = first[u]; i != -1; i = edges[i].next) dfs1(edges[i].to);
        topsort[toplen++] = u;
    }
    
    void dfs2(int u)
    {
        if (sccno[u]) return;
        sccno[u] = scc_cnt;
        bkn[scc_cnt]++;
        for (int i = first[u]; i != -1; i = edges[i].next) dfs2(edges[i].to);
    }
    
    void dfs3(int u)
    {
        if (!vis[u]) return;
        vis[u] = false;
        topsort[toplen++] = u;
        for (int i = ft[u]; i != -1; i = edt[i].next)
        {
            Edge &e = edt[i];
            dg[e.to]--;
            if (dg[e.to] == 0) dfs3(e.to);
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        memset(first, -1, sizeof(first));
        for (int i = 0; i < m; ++i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            edges[i] = Edge(a, b);
            edges[i].next = first[a];
            first[a] = i;
        }
        memset(vis, true, sizeof(vis));
        scc_cnt = toplen = 0;
        for (int i = 1; i <= n; ++i) dfs1(i);
        memset(sccno, 0, sizeof(sccno));
        memset(bkn, 0, sizeof(bkn));
        for (int i = 0; i < n; ++i)
        if (!sccno[topsort[i]])
        {
            scc_cnt++;
            dfs2(topsort[i]);
        }
        memset(dg, 0, sizeof(dg));
        memset(ft, -1, sizeof(ft));
        int tots = 0;
        for (int i = 1; i <= n; ++i)
            for (int j = first[i]; j != -1; j = edges[j].next)
            {
                Edge &e = edges[j];
                if (sccno[i] != sccno[e.to])
                {
                    edt[tots] = Edge(sccno[i], sccno[e.to]);
                    edt[tots].next = ft[sccno[i]];
                    ft[sccno[i]] = tots++;
                    dg[sccno[e.to]]++;
                }
            }
        memset(vis, true, sizeof(vis));
        toplen = 0;
        for (int i = 1; i <= scc_cnt; ++i)
            if (dg[i] == 0) dfs3(i);
        memset(f, 0, sizeof(f));
        for (int i = 0; i < scc_cnt; ++i)
            for (int j = ft[topsort[i]]; j != -1; j = edt[j].next)
            {
                Edge &e = edt[j];
                f[e.to] += f[topsort[i]] + bkn[topsort[i]];
            }
        int ans = 0;
        for (int i = 1; i <= n; ++i)
            if (f[sccno[i]] + bkn[sccno[i]] >= n) ans++;
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    while练习
    运算符
    作业
    [新手必看] 17个常见的Python运行时错误
    作业
    day04
    作业
    算法模板——线段树2(区间加+区间乘+区间求和)
    1798: [Ahoi2009]Seq 维护序列seq
    1708: [Usaco2007 Oct]Money奶牛的硬币
  • 原文地址:https://www.cnblogs.com/albert7xie/p/5040396.html
Copyright © 2011-2022 走看看