• [拓扑排序+记忆化搜索+bfs/dfs] [HAOI2016]食物链


    [HAOI2016]食物链 (nowcoder.com)icon-default.png?t=LA46https://ac.nowcoder.com/acm/problem/20000

    目录

    题目描述

    输入描述:

    输出描述:

    输入

    输出

    BFS写法

    DFS写法


    题目描述

    现在给你n个物种和m条能量流动关系,求其中的食物链条数。

    物种的名称为从1到n编号

    M条能量流动关系形如

    a1 b1

    a2 b2

    a3 b3

    ......

    am-1 bm-1

    am bm

    其中ai bi表示能量从物种ai流向物种bi,注意单独的一种孤立生物不算一条食物链

    输入描述:

    第一行两个整数n和m,接下来m行每行两个整数ai,bi描述m条能量流动关系。 (数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现) 

    1 ≤ N ≤ 100000,0 ≤ m ≤ 200000

    题目保证答案不会爆 int

    输出描述:

    一个整数即食物网中的食物链条数

    示例1

    输入

    10 16
    1 2
    1 4
    1 10
    2 3
    2 5
    4 3
    4 5
    4 8
    6 5
    7 6
    7 9
    8 5
    9 8
    10 6
    10 7
    10 9

    输出

    9

    BFS写法

    在拓扑排序的基础上,

    (出度为0,入度不为零的点即为食物链的最低端,  而且由题意入度和出度都为零的点不算做食物链)

    设想一下,你处于食物链最底端, 如何知道截止到你为止共有几条食物链呢, 你只需要直到截止到你的上一级共有多少条食物链, 以此类推, 可以按照逆过程得到所有食物链底端的食物链条数, 它们之和就是总的食物链条数

     运行时间: 44 ms 占用内存:4472K

    #include <iostream>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N = 5e5+10;
    int n,m;
    int h[N], e[N], ne[N],idx;
    queue<int> q;
    int in[N];
    int res[N]; //记忆化
    void add(int a, int b) 
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    int topSort()
    {
        for(int i = 1; i <= n; i ++)
            if(!in[i]){
                if(h[i]!=-1) res[i]=1;
                q.push(i);
            }
        
        int sum=0;
        while(q.size())
        {
            int t = q.front();
            q.pop();
            for(int i = h[t]; i != -1; i = ne[i]){
                int j = e[i];
                in[j]--;
                res[j] += res[t];
                if(!in[j]) q.push(j);
            }
            if(h[t]==-1) sum += res[t];
        }
        return sum;
    }
    int main()
    {
        cin >> n >> m;
        
        memset(h, -1, sizeof h);
        int a, b;
        while(m--)
        {
            scanf("%d%d", &a, &b);
            add(a, b);
            in[b]++;
        }
        cout << topSort();
        return 0;
    }

    DFS写法

    与上一种写法思路差不多,但程序的递推流程截然相反,一个是由顶至下更新,一个是自底而上

    运行时间51ms  占用内存8568KB(内存耗费较为大)

    #include <iostream>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N = 5e5+10;
    int n,m;
    int h[N], e[N], ne[N],idx;
    int in[N];
    int res[N];
    void add(int a, int b) 
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    int dfsTop(int u)
    {
        if(h[u] == -1) return 1;
        if(res[u] != -1) return res[u]; //若是在之前的递归中已更新过,则直接可用
        int t = 0;
        for(int j = h[u]; j != -1; j =ne[j]){
            int k = e[j];
            t += dfsTop(k);
        }
        return res[u] = t;  //更新并返回
    }
    int main()
    {
        cin >> n >> m;
        
        memset(h, -1, sizeof h);
        int a, b;
        while(m--)
        {
            scanf("%d%d", &a, &b);
            add(a, b);
            in[b]++;
        }
    
        int sum = 0;
        memset(res, -1, sizeof res);
        for(int i = 1; i <= n; i ++)
            if(!in[i] && h[i] != -1)
                sum += dfsTop(i);
    
        cout << sum;
        return 0;
    }

    本文来自博客园,作者:泥烟,CSDN同名, 转载请注明原文链接:https://www.cnblogs.com/Knight02/p/15799037.html

  • 相关阅读:
    解决<c:if>无else的问题
    极限挑战----3小时完成OA系统(失败)
    jstl的if标签和forEach标签的解析
    EL表达式
    JSP静态包含和动态包含的区别
    JSP九大隐式对象和四大域对象-----面试
    mybatis学习01--基础认识
    怎样将本地的代码上传到github
    随机数的生成,静态导入,可变参数的方法,方法重载,浮点数的比较
    zookeeper学习2
  • 原文地址:https://www.cnblogs.com/Knight02/p/15799037.html
Copyright © 2020-2023  润新知