[洛谷]P4017 最大食物链计数(java代码实现)

1.题意及要点分析

a) 求出从顶级消费者到生产者所有连线数目的和再取模;

b) 需要进行取模的题在每次的中间结果需要取模,防止太大。如本题从某一个顶级消费者为起点到生产者为终点所有连线的和求,其中的每一步都需要取模。在最后计算以所有顶级消费者为起点的连线和时,需要再取一次模。

2.代码示例

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static final int MOD = 80112002;

    static ArrayList<ArrayList<Integer>> eat; 
    // 二维可变数组,存储该序号代表生物的食物(被吃者)

    static int[] dp; 
    // 存储以该生物为起点至生产者的食物链数目

    static boolean[] consumed; 
    // 标记该序号代表生物是否被吃
    // true表示可以被吃,false表示不可被吃,即顶级消费者

    static int ans;

    static int f(int now) {
        if (eat.get(now).isEmpty()) return dp[now] = 1; 
        // 如果数组eat某序号对应的一组元素为空说明它谁也吃不了,即为生产者,
        // 返回1进行计数,表示找到了一条食物链

        if (dp[now] != 0) return dp[now]; 
        // 如果某一dp不为零,说明其已被计算过,
        // 直接输出,不必再次计算(记忆化,减少时间消耗)

        int res = 0;
        for (int nxt : eat.get(now)) {
            res += f(nxt); 
            // f(x)代表以序号x为起点到生产者的所有食物链的数目. 
            //假设x的食物为a,b,c,... 则f(x)=f(a)+f(b)+f(c)+...

            res %= MOD;    // 取模,防止溢出,这里是符合提议要求的
        }
        return dp[now] = res;
    }

    public static void main(String[] args) throws IOException {

        // 数据输入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        eat = new ArrayList<>();
        dp = new int[n + 1];
        consumed = new boolean[n + 1];

        for (int i = 0; i <= n; i++) {
            eat.add(new ArrayList<>());
        }

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            eat.get(y).add(x);
            consumed[x] = true;
        }

        // 寻找顶级消费者,计算所有从顶级消费者为起点到生产者的食物链之和

        for (int i = 1; i <= n; i++) {
            if (!consumed[i]) {
                ans = (ans + f(i))%MOD; // 取模,防止溢出,符合题意
            }
        }

        System.out.println(ans);
        br.close();
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值