最大食物链计数 (记忆化搜索) (2023-02-08)

题目链接: https://vjudge.net/contest/537778#problem/C

题意

给你 n 个动物,m 条他们之间吃与被吃的关系。

计算总共食物链的条数。(模上80112002)

(n <= 5e3, m <= 5e5)

思路

记录每一个动物的出边(被吃掉)和入边(可以吃掉),然后沿着食物链方向,ret[i] = sum(ret[out[i]]),记忆化搜索下去。

这题还能用拓扑排序做。但是思路都大差不差。如果用拓扑就是正向的dp,一路先解决子问题再解决最终的问题。如果是记忆化搜索就是从最终的问题出发,向前要求得到每一个子问题的结果。

复杂度: O(m)

代码

#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>

#define orep(i,l,r) for(auto i = (l); i < (r); ++i)
#define NL          putchar(10);
#define magic 80112002;

const int maxN = 5e3+10;
int dp[maxN];
std::vector<int> out[maxN], in[maxN];
int stk[maxN]; int c;

int down(int x) {
  if (!in[x].size()) { return 1; }
  if (dp[x]) { return dp[x]; }
  int me = 0;
  orep(i, 0u, in[x].size()) {
    me = (me + down(in[x][i])) % magic;
  }
  return dp[x] = me;
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  orep(i, 0, m) {
    int a, b; scanf("%d%d", &a, &b);
    out[a].push_back(b);
    in[b].push_back(a);
  }

  int ret = 0;
  orep(i, 1, n+1) {
    if (!out[i].size()) { ret = (ret + down(i)) % magic; }
  }
  printf("%d", ret);

  return 0;
}