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

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

我们可以从这题中学习到拓扑排序的一个模板。
入度in[N] 出度out[N]的初始化数值
通过二维vector<int> neigh[N]来存储邻接图
num[N]来存储每个结点的答案数值
遍历入度来找到入度为0的点添加至队列queue<int>q
遍历队列的基本模板
while (!que.empty())
{
temp = que.front();
que.pop();
//遍历这个结点所有连接的结点
for (int i = 0; i < neigh[temp].size(); ++i)
{
//把这些连接点的入度都减1 并且让他们的num值都加上前一个结点的num值
in[neigh[temp][i]]--;
num[neigh[temp][i]] = (num[temp] + num[neigh[temp][i]]) % mod;
if (in[neigh[temp][i]] == 0)
que.push(neigh[temp][i]);//如果入度为0 就把这个结点加入队列
}
}
最后遍历out数组找到出度为0的点 num值累加为ans即为但答案。
动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序的更多相关文章
- 洛谷 P4017 最大食物链计数
洛谷 P4017 最大食物链计数 洛谷传送门 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写 ...
- 洛谷 P4017 最大食物链计数 题解
P4017 最大食物链计数 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧 ...
- 洛谷——P4017 最大食物链计数
P4017 最大食物链计数 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧 ...
- 洛谷 P4017 最大食物链计数 (拓扑排序,思维)
题意:有\(n\)个点,连\(m\)条边,求最多有多少条食物链(从头走到为有多少条路径). 题解:之前抽了点时间把拓扑排序补完了,这题其实就是一道拓扑排序的裸题.关于拓扑排序: 1.首先,我们用\ ...
- 洛谷P4017 最大食物链计数
拓扑排序板子题 #include <iostream> #include <cstdio> #include <cstring> #include <queu ...
- 洛谷P4581 [BJOI2014]想法(玄学算法,拓扑排序)
洛谷题目传送门 萝卜大毒瘤 题意可以简化成这样:给一个DAG,求每个点能够从多少个入度为\(0\)的点到达(记为\(k\)). 一个随机做法:给每个入度为\(0\)的点随机一个权值,在DAG上求出每个 ...
- 洛谷P4645 [COCI2006-2007 Contest#7] BICIKLI [Tarjan,拓扑排序]
题目传送门 BICIKLI 题意翻译 给定一个有向图,n个点,m条边.请问,1号点到2号点有多少条路径?如果有无限多条,输出inf,如果有限,输出答案模10^9的余数. 两点之间可能有重边,需要看成是 ...
- 洛谷P4017 最大食物链数量 dfs
老规矩,传送门 做题从头到尾的思路: 1. 这个题明显就是dfs数数量了,简单,邻接矩阵干他! TLE警告,8个点 额... 2. 老师说这玩意不能邻接矩阵?没事,还有邻接表,再来! 再次TLE 8个 ...
- 洛谷P3065 [USACO12DEC]第一!First!(Trie树+拓扑排序)
P3065 [USACO12DEC]第一!First! 题目链接:https://www.luogu.org/problemnew/show/P3065 题目描述 Bessie一直在研究字符串.她发现 ...
随机推荐
- 初识python(2)
目录 引言 数据类型 字典 集合 元组 布尔值 用户交互 格式化输出 运算符 增量赋值 链式赋值 交叉赋值 解压赋值 逻辑运算符 成员运算符 身份运算符 引言 小伙伴们昨天已经讲了一点python的数 ...
- MySQL 中如何归档数据
归档,在 MySQL 中,是一个相对高频的操作. 它通常涉及以下两个动作: 迁移.将数据从业务实例迁移到归档实例. 删除.从业务实例中删除已迁移的数据. 在处理类似需求时,都是开发童鞋提单给 DBA, ...
- 微信小程序下拉框实现
小程序中是没有直接的下拉框标签可以使用的,所以下拉框需要手动写,或者使用框架 因为考虑到下拉框展开的时候,可能需要遮挡住其余的样式,这里就用的cover-view标签.(不考虑遮挡的可以换成普通的vi ...
- 快速整明白Redis中的整数集合到底是个啥
整数集合简介 整数集合(intset)是Redis集合数据类型的内部编码之一,当集合数据类型中的元素都是整数并且元素数量较少的时候,Redis就使用整数集合作为内部编码. 整数集合(intset)中可 ...
- 题解 P1659 【[国家集训队]拉拉队排练】
一眼可得PAM 如果没学过PAM的可以看这里:PAM学习小结 我们令PAM上多记录一个信息\(sum\),表示该节点表示串在原串上出现了多少次. 当我们处理完了\(sum\),对于长度\(len\)为 ...
- VBS文件无限循环解决办法
VBS文件无限循环解决办法,也就相当于编程中的停止运行指令. 那么如何关掉VBS文件呢?当然关机后会自动关掉,还有另外一种方法就是,在"任务管理器"中找到进程"WScri ...
- java 实现装饰器设计模式
package com.gylhaut.base; /** * 装饰器 * 类与类之间的关系 * 1.依赖:形参(局部变量) * 2.关联:属性 * 聚合 属性 整体和部分 不一致的生命周期 人和手 ...
- [SWPU2019] NETWORK
[SWPU2019]Network(TTL隐写) 1.题目概述 2.解题过程 文档中的数字代表什么呢?会不会是RGB? 看了一下以前做过的题目,好像并不是 那是什么呢?百度告诉我这是TTL隐写,哇,长 ...
- 学习HashMap源码
HashMap简介 HashMap是一种存储K-V类型的容器,HashMap底层数据结构为数组+链表+红黑树(jdk 1.8新增),它根据键的HashCode值存储数据,获取元素的时间复杂度为O( ...
- Java将彩色PDF转为灰度
本文以Java代码为例介绍如何实现将彩色PDF文件转为灰度(黑白)的PDF文件,即:将PDF文档里面的彩色图片或者文字等通过调用PdfGrayConverter.toGrayPdf()方法转为文档页面 ...