动态规划的引入 P4017 最大食物链计数【拓扑排序的条数计算】
题目
https://www.luogu.com.cn/problem/P4017
题目分析
题目的意思是从入度为0的起点开始,到出度为0的终点结束,统计这样的路径一共有多少条
这样就涉及到了拓扑排序的概念
拓扑排序的寻找方法
- 从图中找到一个
没有前驱
的顶点输出。(可以遍历,也可以用优先队列维护)
删除以这个点为起点的边
。(它的指向的边删除,为了找到下个没有前驱的顶点)
- 重复上述,直到最后一个顶点被输出。如果还有顶点未被输出,则说明有环!
使用的数据结构以及算法
由于图中存在的起点(入度为零的点)可能不止一个,那个这个路径寻找的过程要执行多次,所以要先把这样的起点入队
然后执行拓扑排序的寻找方法,一旦入队变为零就将该节点入队
由于图中出度为零的点也不止一个,所以将图中所有出度为0的节点的拓扑路径书相加就是答案
代码
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int dp[5002]; vector<int>edges[5003]; int in[5003], out[5003]; int n, m; queue<int>list; int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); //edges[a][b] = 1; edges[a].push_back(b); in[b]++; out[a]++; } for (int i = 1; i <=n; i++) { if (in[i] == 0) { list.push(i); dp[i] = 1; } } while (!list.empty()) { int temp = list.front(); list.pop(); for (int i =0; i <edges[temp].size(); i++) { in[edges[temp][i]]--; if (in[edges[temp][i]] == 0)list.push(edges[temp][i]); dp[edges[temp][i]] =( dp[temp] + dp[edges[temp][i]])%80112002; } } int sum = 0; for (int i = 1; i <=n; i++) { if (out[i] == 0) sum = (sum + dp[i]) % 80112002; } printf("%d", sum); }
注意拓扑排序的习题中队列的使用