动态规划的引入 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);
}

注意拓扑排序的习题中队列的使用

posted @ 2020-06-13 20:07  Jason66661010  阅读(144)  评论(0编辑  收藏  举报