洛谷P4017 最大食物链计数

  这是洛谷一题普及/提高-的题目,也是我第一次做的一题 图上动态规划/拓扑排序 ,我认为这题是很好的学习拓扑排序的题目。

    在这题中,我学到了几个名词,入度,出度,及没有环的有向图必定有入度为0的点。通过与题干分析可知,入度为0就是最佳生产者,出度为0就是最佳消费者。题干的大意就是找出图中一共有几条食物链是从最佳生产者指向最佳消费者。

    我在题解区学习了拓扑排序后的第一次题解,然而只过了一个测试点,一片WA声。。

  1. 1 //动态规划 洛谷P4017 最大食物链计数
  2. 2 #include<iostream>
  3. 3 #include<cmath>
  4. 4 #include<vector>
  5. 5 #include<queue>
  6. 6 using namespace std;
  7. 7 const int mod = 80112002;
  8. 8 const int MAX = 5e3 + 5;
  9. 9 int in[MAX], out[MAX];//两个数组 记录结点的入度和出度
  10. 10 vector<int>neigh[MAX]; //vector的二维数组 可以存放图的邻接关系
  11. 11 queue<int>que;//队列 每次将入度为0的点入队循环
  12. 12 int num[MAX];//记录每一个点的值 就是到这个点有几条路径
  13. 13 int ans;
  14. 14 int main()
  15. 15 {
  16. 16 int n, m;
  17. 17 int x, y;//用来输入被捕食和捕食的生物编号
  18. 18 cin >> n >> m;//n是生物数量 m是食物链数量 也可以说n就是结点数 m就是有向边的数量
  19. 19 for (int i = 0; i < m; ++i)
  20. 20 {
  21. 21 cin >> x >> y;
  22. 22 out[x]++, in[y]++;//图上是由x-->y所以入度y++ 出度x++
  23. 23 neigh[x].push_back(y);//存放x指向的结点 便于后面遍历
  24. 24 }
  25. 25
  26. 26 for (int i = 1; i <= n; ++i)
  27. 27 {
  28. 28 //遍历寻找入度为0的点 也就是最佳生产者 加入队列
  29. 29 if (!in[i])
  30. 30 {
  31. 31 num[i] = 1;//将入度为0的点的num设为1 自己到自己有一条路径
  32. 32 que.push(i);
  33. 33 break;
  34. 34 }
  35. 35 }
  36. 36 int temp;
  37. 37 while (!que.empty())
  38. 38 {
  39. 39 temp = que.front();
  40. 40 que.pop();
  41. 41 //遍历这个结点所有连接的结点
  42. 42 for (int i = 0; i < neigh[temp].size(); ++i)
  43. 43 {
  44. 44 //把这些连接点的入度都减1 并且让他们的num值都加上前一个结点的num值
  45. 45 in[neigh[temp][i]]--;
  46. 46 num[neigh[temp][i]] = (num[temp] + num[neigh[temp][i]]) % mod;
  47. 47 if (in[neigh[temp][i]] == 0)
  48. 48 que.push(neigh[temp][i]);//如果入度为0 就把这个结点加入队列
  49. 49 }
  50. 50 }
  51. 51 for (int i = 1; i <= n; ++i)
  52. 52 {
  53. 53 //寻找出度为0的结点 出度为0说明就是最佳消费者 也就是最后一个终点结点
  54. 54 if (out[i] == 0)
  55. 55 {
  56. 56 ans = num[i];
  57. 57 break;
  58. 58 }
  59. 59
  60. 60 }
  61. 61 cout << ans;
  62. 62
  63. 63 return 0;
  64. 64
  65. 65 }

经过我的思考与debug,我发现,不一定只有一个最佳生产者,也不一定只有一个最佳消费者,所以起点和终点应该有很多个,所以ans应该累加,起始队列的添加应该遍历完数组,可能添加多个起点。

修改后的代码:

  1. 1 //动态规划 洛谷P4017 最大食物链计数
  2. 2 #include<iostream>
  3. 3 #include<cmath>
  4. 4 #include<vector>
  5. 5 #include<queue>
  6. 6 using namespace std;
  7. 7 const int mod = 80112002;
  8. 8 const int MAX = 5e3 + 5;
  9. 9 int in[MAX], out[MAX];//两个数组 记录结点的入度和出度
  10. 10 vector<int>neigh[MAX]; //vector的二维数组 可以存放图的邻接关系
  11. 11 queue<int>que;//队列 每次将入度为0的点入队循环
  12. 12 int num[MAX];//记录每一个点的值 就是到这个点有几条路径
  13. 13 int ans;
  14. 14 int main()
  15. 15 {
  16. 16 int n, m;
  17. 17 int x, y;//用来输入被捕食和捕食的生物编号
  18. 18 cin >> n >> m;//n是生物数量 m是食物链数量 也可以说n就是结点数 m就是有向边的数量
  19. 19 for (int i = 0; i < m; ++i)
  20. 20 {
  21. 21 cin >> x >> y;
  22. 22 out[x]++, in[y]++;//图上是由x-->y所以入度y++ 出度x++
  23. 23 neigh[x].push_back(y);//存放x指向的结点 便于后面遍历
  24. 24 }
  25. 25
  26. 26 for (int i = 1; i <= n; ++i)
  27. 27 {
  28. 28 //遍历寻找入度为0的点 也就是最佳生产者 加入队列
  29. 29 if (!in[i])
  30. 30 {
  31. 31 num[i] = 1;//将入度为0的点的num设为1 自己到自己有一条路径
  32. 32 que.push(i);//入度为0的点有很多个
  33. 33
  34. 34 }
  35. 35 }
  36. 36 int temp;
  37. 37 while (!que.empty())
  38. 38 {
  39. 39 temp = que.front();
  40. 40 que.pop();
  41. 41 //遍历这个结点所有连接的结点
  42. 42 for (int i = 0; i < neigh[temp].size(); ++i)
  43. 43 {
  44. 44 //把这些连接点的入度都减1 并且让他们的num值都加上前一个结点的num值
  45. 45 in[neigh[temp][i]]--;
  46. 46 num[neigh[temp][i]] = (num[temp] + num[neigh[temp][i]]) % mod;
  47. 47 if (in[neigh[temp][i]] == 0)
  48. 48 que.push(neigh[temp][i]);//如果入度为0 就把这个结点加入队列
  49. 49 }
  50. 50 }
  51. 51 for (int i = 1; i <= n; ++i)
  52. 52 {
  53. 53 //寻找出度为0的结点 出度为0说明就是最佳消费者 也就是最后一个终点结点
  54. 54 if (out[i] == 0)
  55. 55 {
  56. 56 ans = (ans + num[i]) % mod;
  57. 57 //出度为0的点也可能有很多个 不能break 要累加答案
  58. 58 }
  59. 59
  60. 60 }
  61. 61 cout << ans;
  62. 62
  63. 63 return 0;
  64. 64
  65. 65 }

完美通过

我们可以从这题中学习到拓扑排序的一个模板。

  1. 入度in[N] 出度out[N]的初始化数值
  2. 通过二维vector<int> neigh[N]来存储邻接图
  3. num[N]来存储每个结点的答案数值
  4. 遍历入度来找到入度为0的点添加至队列queue<int>q
  5. 遍历队列的基本模板
  6. while (!que.empty())
  7. {
  8. temp = que.front();
  9. que.pop();
  10. //遍历这个结点所有连接的结点
  11. for (int i = 0; i < neigh[temp].size(); ++i)
  12. {
  13. //把这些连接点的入度都减1 并且让他们的num值都加上前一个结点的num值
  14. in[neigh[temp][i]]--;
  15. num[neigh[temp][i]] = (num[temp] + num[neigh[temp][i]]) % mod;
  16. if (in[neigh[temp][i]] == 0)
  17. que.push(neigh[temp][i]);//如果入度为0 就把这个结点加入队列
  18. }
  19. }
  20. 最后遍历out数组找到出度为0的点 num值累加为ans即为但答案。

动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序的更多相关文章

  1. 洛谷 P4017 最大食物链计数

    洛谷 P4017 最大食物链计数 洛谷传送门 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写 ...

  2. 洛谷 P4017 最大食物链计数 题解

    P4017 最大食物链计数 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧 ...

  3. 洛谷——P4017 最大食物链计数

    P4017 最大食物链计数 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧 ...

  4. 洛谷 P4017 最大食物链计数 (拓扑排序,思维)

    题意:有\(n\)个点,连\(m\)条边,求最多有多少条食物链(从头走到为有多少条路径). 题解:之前抽了点时间把拓扑排序补完了,这题其实就是一道拓扑排序的裸题.关于拓扑排序: ​ 1.首先,我们用\ ...

  5. 洛谷P4017 最大食物链计数

    拓扑排序板子题 #include <iostream> #include <cstdio> #include <cstring> #include <queu ...

  6. 洛谷P4581 [BJOI2014]想法(玄学算法,拓扑排序)

    洛谷题目传送门 萝卜大毒瘤 题意可以简化成这样:给一个DAG,求每个点能够从多少个入度为\(0\)的点到达(记为\(k\)). 一个随机做法:给每个入度为\(0\)的点随机一个权值,在DAG上求出每个 ...

  7. 洛谷P4645 [COCI2006-2007 Contest#7] BICIKLI [Tarjan,拓扑排序]

    题目传送门 BICIKLI 题意翻译 给定一个有向图,n个点,m条边.请问,1号点到2号点有多少条路径?如果有无限多条,输出inf,如果有限,输出答案模10^9的余数. 两点之间可能有重边,需要看成是 ...

  8. 洛谷P4017 最大食物链数量 dfs

    老规矩,传送门 做题从头到尾的思路: 1. 这个题明显就是dfs数数量了,简单,邻接矩阵干他! TLE警告,8个点 额... 2. 老师说这玩意不能邻接矩阵?没事,还有邻接表,再来! 再次TLE 8个 ...

  9. 洛谷P3065 [USACO12DEC]第一!First!(Trie树+拓扑排序)

    P3065 [USACO12DEC]第一!First! 题目链接:https://www.luogu.org/problemnew/show/P3065 题目描述 Bessie一直在研究字符串.她发现 ...

随机推荐

  1. MySQL第一讲概论

    MySQL 后期内容 Python 今日内容概要 MySQL的概念 数据库软件的安装及使用 配置文件介绍 数据库常用命令(库操作.表操作.记录操作) 今日内容详细 什么是数据库 1.单机游戏 本地保存 ...

  2. numpy.random模块用法小结

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9751471.html 1.np.random.random()函数参数 np.random.r ...

  3. LeetCode-091-解码方法

    解码方法 题目描述:一条包含字母 A-Z 的消息通过以下映射进行了 编码 : 'A' -> 1 'B' -> 2 ... 'Z' -> 26 要 解码 已编码的消息,所有数字必须基于 ...

  4. Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean

    Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...

  5. [2022-3-5] OICLASS-USACO提高组模拟赛2 B: Cow Frisbee

    题意 在一排奶牛中,对于每两头奶牛,如果两头奶牛之间没有奶牛比这两头高,则答案累加这两头奶牛的距离. 分析 设现在分析的奶牛为第 \(i\) 头,它向左扔出了一个飞盘,显然它的飞行高度为奶牛的高度.飞 ...

  6. 小程序WXS 模块

    WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构 WXS中定义的函数可以在wxml文件中使用,可以用它来当过滤器使用 WXS以.wxs扩展名结尾,文件中 ...

  7. 2.4 C++STL deque容器详解

    文章目录 2.4.1 引入 2.4.2 代码示例 2.4.3 代码运行结果 2.4.4 具体案例 总结 2.4.1 引入 deque容器类比vector容器来学习. deque为双向开口容器,见下图. ...

  8. 用协程实现高并发I/O(async)

    对于并发要求比较法的I/O需求,可以用python的协程去处理. 重点: 1启动协程必须做一次函数调用 2协程激活只占用1kb内存,所以协程很多也问题不大 3这种效果需要使用关键字async和awai ...

  9. 昇腾CANN论文上榜CVPR,全景图像生成算法交互性再增强!

    摘要:近日,CVPR 2022放榜,基于CANN的AI论文<Interactive Image Synthesis with Panoptic Layout Generation>强势上榜 ...

  10. ZYNQ SGI、PPI、SPI三种中断的实例(含代码)

    ZYNQ中断分为3类: SGI(Software Generated Interrupts)软件中断 PPI(Private Peripheral Interrupts)私有外设中断 SPI(Shar ...