首页 > 其他分享 >洛谷P4017 最大食物链计数

洛谷P4017 最大食物链计数

时间:2024-06-02 22:28:20浏览次数:18  
标签:食物链 排序 洛谷 int 节点 vector include P4017 left

题目信息

题目要求

样例输入/输出 

算法简介 

要知道题目需要用到什么样的算法,首先得捋清楚题目的意思

比如这个题目,我们读题后可以获得这样的信息:

(1)节点之间构成有向边

(2)所有边不会构成环

(3)需要求的所有的边没有边权而且一定是从入度为零的节点到出度为零的节点

基于以上三点我们基本可以确定可以尝试用拓扑排序解决问题。

拓扑排序的定义如下:

 

算法过程

拓扑排序的过程十分简单,借助bfs完成排序,首先把所有入度为零的节点入队,然后把这些点能到的节点的度数都减去一,再将这个节点出队,如果有节点减到0了那就证明这个节点可以入队作为下一轮节点筛选的基准。这样的过程一直到队列为空。

代码模板

vector<int> topo_sort(const int &k, vector<vector<int>>& edges) {
        vector<vector<int>> g(k);
        vector<int> order, left(k, 0);
        for (auto& edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            g[x].push_back(y);
            ++left[y];
        }
        queue<int> q;
        for (int i = 0; i < k; i++) {
            if (left[i] == 0) q.push(i);
        }
        while (!q.empty()) {
            int node = q.front(); q.pop();
            order.push_back(node + 1);
            for (auto& x : g[node]) {
                --left[x];
                if (left[x] == 0) q.push(x);
            }
        }
        return order.size() == k ? order : vector<int> ();
    }

代码细节

拓扑排序一般使用邻接矩阵存图,用vector将每个节点可以到达的点都放在相应的数组中,再放的同时将可以到达的节点的入度加上一,这样迭代完所有的节点之后整张图就存下来了。

另外在实现排序的时候,利用了队列的扩展性,将所有的节点分层入队,再将每一层的节点能到达的所有节点全部遍历一遍,并将其入度减一,如果发现某节点入度变成0了,就将这个节点入队作为下一层的基准。迭代完成后将这个节点弹出队列即可。这样一直到队列为空时,整个拓扑排序的算法完成。注意如果需要得到排序列表的话,在每个节点出队列前将其压入目标列表ordoer即可。

解题思路

首先我们可以将每次输入看成条从相对消费者到相对生产者的一条有向无权边,这样可以实现边输入边建图。

代码如下:

for (int i = 0, u, v; i < m; i++) {
        cin >> u >> v;
        graph[v].push_back(u);
        ++left[u];
    }

建完图之后,我们需要做的就就是进行拓扑排序,这个过程并不复杂,其实就是一个简单的bfs。

不过值得一提的是这个题是要求所有从入度为零的点到所有出度为零的点的所有边的总和

这样的话我们需要一个额外的数组cnt,这个数组在进行拓扑排序的同时不断更新,即从入度为零的点开始,并且将入度为零的点初始化cnt的值为1,每次都把其结果加到能到达的点上面,这样最后再遍历一遍所有出度为零的点,将它们所有的cnt求个和即可

代码细节如下

    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (left[i] == 0) {
            q.push(i);
            cnt[i] = 1;
        }
    }
    while (!q.empty()) {
        int node = q.front(); q.pop();
        for (auto& x : graph[node]) {
            --left[x];
            cnt[x] += cnt[node]; 
            cnt[x] %= MOD;
            if (left[x] == 0) q.push(x);
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (graph[i].size() == 0) {
            ans += cnt[i];
            ans %= MOD;
        }
    }

全部代码

#include<iostream>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<unordered_map>
#include<algorithm>
using namespace std;

int init = [] {
    cin.tie(nullptr)->sync_with_stdio(false);
    return 0;
}();

const int MOD = 80112002;
typedef pair<int, int> PII;

int main(){
    int n, m, ans = 0;
    cin >> n >> m;
    vector<vector<int>> graph(n + 1);
    vector<int> left(n + 1, 0);
    vector<int> cnt(n + 1, 0);
    for (int i = 0, u, v; i < m; i++) {
        cin >> u >> v;
        graph[v].push_back(u);
        ++left[u];
    }
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (left[i] == 0) {
            q.push(i);
            cnt[i] = 1;
        }
    }
    while (!q.empty()) {
        int node = q.front(); q.pop();
        for (auto& x : graph[node]) {
            --left[x];
            cnt[x] += cnt[node]; 
            cnt[x] %= MOD;
            if (left[x] == 0) q.push(x);
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (graph[i].size() == 0) {
            ans += cnt[i];
            ans %= MOD;
        }
    }
    cout << ans << endl;
    return 0;
}

标签:食物链,排序,洛谷,int,节点,vector,include,P4017,left
From: https://blog.csdn.net/m0_74246669/article/details/139333592

相关文章

  • 洛谷1803 凌乱的yyy / 线段覆盖 【贪心】
    凌乱的yyy/线段覆盖题目背景快noip了,yyy很紧张!题目描述现在各大oj上有nnn个比赛,每个比赛的开始、结束的时间点是知道的。yyy认为,参加越多的比赛,noip就能......
  • 洛谷1090 合并果子 【贪心】
    [NOIP2004提高组]合并果子/[USACO06NOV]FenceRepairG题目描述在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出......
  • 关于洛谷获得数据怪谈
    免责声明:本文仅用于测试键盘性能,输入内容概不负责。在洛谷有时输入数据仅有几个数字,但是出于某些原因无法获得输入数据,但是手贱非常想要获得,于是尝试一种特殊方法。示例题目:P1014[NOIP1999普及组]Cantor表尝试提交以下代码:#include<iostream>usingnamespacestd;intn......
  • 洛谷 P8725 [蓝桥杯 2020 省 AB3] 画中漂流 的题解
    题目大意传送门思路考虑使用时空复杂度为O(tm)O(tm)......
  • 洛谷 P8614 [蓝桥杯 2014 省 A] 波动数列 的题解
    题目大意求满足和为sss且ti=......
  • 【回溯】洛谷P1135奇怪的电梯
    题目描述呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 ......
  • 博弈论——洛谷P6560 [SBCOI2020] 时光的流逝
    [SBCOI2020]时光的流逝题目背景时间一分一秒的过着,伴随着雪一同消融在了这个冬天,或许,要是时光能停留在这一刻,该有多好啊。......“这是...我在这个小镇的最后一个冬天了吧。”“嗯,你可不能这辈子都呆在这个小镇吧。外面的世界很大呢,很大很大...”“唔...外面的世界...突然......
  • 洛谷P1087 FBI树
    洛谷P1087递归建立树,根据当前树的类型,选择“F”“B”“I”voidbuild(intdepth,intstart,intend,introot){if(depth>=n+1)return;intcurrent=root;intflag=check(start,end);if(flag==0)t[current].self='B';elseif(flag==......
  • 中序后序到先序 洛谷P1030
    洛谷P1030输入中序先序序列,输出后序l1-l2为当前中序遍历序列l3-l4为当前后序遍历序列#include<bits/stdc++.h>usingnamespacestd;stringa,b;structnode{charself;intleft,right;}t[200];voidbuild(intl1,intl2,intl3,intl4){for(int......
  • 洛谷P1996约瑟夫问题
    题目描述 P996约瑟夫问题n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 11 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n−1 ......