P4017 最大食物链计数

题目传送门

一、试题讲解

https://www.cnblogs.com/CJYBlog/p/12198894.html

二、拓扑排序完整代码

#include <bits/stdc++.h>

using namespace std;
const int N = 5005;         //生物种类上限
const int M = 500005;       //吃与被吃的关系数上限
const int MOD = 80112002;   //最大食物链数量模
int n;                      //生物种类
int m;                      //吃与被吃的关系数
int ans;                    //为最大食物链数量模上 80112002 的结果
vector<int> edge[N];        //保存DAG图的邻接表
queue<int> q;               //广搜的队列
int f[N];                   //每个生物种类的食物链最长值
int ind[N];                 //每个生物种类的入度
int out[N];                 //每个生物种类的出度

/**
 总结:
 1、谁向谁有一条有向边是需要强调的,x->y与 y->x是完全不同的。本题是说x被y吃掉,记录的是这个关系,
 即x->y有一条有向边。
 2、需要进行模的题,需要每一步操作结果时,都进行一次MOD操作,防止中间过程数据过大。
 3、获得的所有食物链数量加在一起,再MOD,才是结果。
 4、DAG+广度优先搜索= "拓扑排序" !!! !!!!目的:使得在搜到点x时,所有能达到点x的点,已经被搜过了。
 5、拓扑排序思路:把入度为0的入到队列,然后找到它的所有出边,对接点入度-1,如果对接点入度为0,则再入队列。
 6、每一个以当前结点为终止结点的路径条数,等于上一级的N个结点,每个结点条数的和。
 7、在DAG的广度搜索中+动态规划是本题的难点,注意base case的理解。
 8、入度为0的,是第一批入队列的,它们是食物链的底层(草根)。出度为0的是食物链的顶层,是老虎,鹰,鲨鱼等。
 9、出度是否为0,是判断是不是再继续入队列的条件。
 10、入度为0的所有结点,它们的食物链条数和就是答案
 11、与深度优先不同,拓扑排序,需要同时维护出度和入度,出度在录入数据后,维护不变;入度随算法的深入,
 一直在-1,直到为0.
 */

int main() {
    cin >> n >> m;
    //m种关系
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;          //x被y吃掉
        out[x]++;               //点x的出度+1
        ind[y]++;               //点y的入度+1
        edge[x].push_back(y);   //用邻接表记录下食物链的关系,x被y吃掉,由x向y引一条有向边
    }
    //找到所有入度为0的点,放入广度优先搜索的队列
    for (int i = 1; i <= n; i++) if (!ind[i]) q.push(i), f[i] = 1; 
    //f[i]=1:base case,它到它的每个孩子都有一条出边,就是一条路径

    //广度优先搜索DAG,就是拓扑排序的模板
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        for (int i = 0; i < edge[x].size(); i++) { //遍历所有出边
            int y = edge[x][i];                    //目标结点
            f[y] = (f[x] + f[y]) % MOD;         //在计算f[y]之前, f[x]都是计算过的了。
            //对接点入度-1,抹去这条入边
            ind[y]--;
            //如果入度为0,则入队列,准备处理它
            if (!ind[y]) q.push(y);
        }
    }
    //遍历所有结点,如果出度为0,描述
    for (int i = 1; i <= n; i++) if (!out[i]) ans = (ans + f[i]) % MOD;
    cout << ans << endl;
    return 0;
}
上一篇:洛谷 P4017 最大食物链计数 (拓扑排序,思维)


下一篇:故障定级标准