# ZJUT4补题计划Day1_C. Book

C. Book

题目传送门:

题目传送门

题面:

在这里插入图片描述

题目大意:

一本书有n个章节,每个章节都有可能有前置章节,对于某个章节i只有理解完他的全部前置章节才能理解章节i,每次看书从第一章看到最后一章,求最少要读几次能理解全部章节,没办法理解所有章节则输出-1。

思路A:

先写个dp。

对于某个章节a,如果他的前置章节b<a,由于读书次序从小到大,那么ab能同时理解,只要读1遍: d p [ a ] = m a x ( d p [ a ] , d p [ b ] ) dp[a]=max(dp[a],dp[b]) dp[a]=max(dp[a],dp[b])
否则就要读2遍:
d p [ a ] = m a x ( d p [ a ] , d p [ b ] + 1 ) dp[a]=max(dp[a],dp[b]+1) dp[a]=max(dp[a],dp[b]+1)

代码A:

#include<iostream>
#include<vector>
#include<queue>

using namespace std;
const int N = 2e5 + 10;
int d[N], dp[N];
//每个点的入度,每章节的次数
vector<int> g[N];//存每个章节需要理解的各章节
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n;
        for (int i = 1; i <= n; i++) {
            g[i].clear();
            dp[i] = 0;
            d[i] = 0;
        }
        scanf("%d", &n);
        int k, x;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k);
            d[i] = k;
            while (k--) {
                scanf("%d", &x);
                g[x].push_back(i);
            }
        }
        queue<int> q;
        for (int i = 1; i <= n; i++) {
            if (!d[i])q.push(i), dp[i] = 1;
            //先读第一遍
            //已经读完的入队
        }
        while (q.size()) {
            int t = q.front();
            q.pop();
            for (auto it:g[t]) {
                //遍历以已读完的章节为前置章节的章节
                d[it]--;
                //读完一个前置了,门槛--;
                if (t > it)
                    dp[it] = max(dp[it], dp[t] + 1);
                else dp[it] = max(dp[it], dp[t]);
                if (d[it] == 0)q.push(it);
            }
        }
        int ans = 0;
        int flag= 1;
        for (int i = 1; i <= n; i++) {
            ans = max(ans, dp[i]);
            if (d[i])flag = 0;
        }
        if (flag == 0)cout << "-1" << endl;
        //自环了
        else cout << ans << endl;
    }
    return 0;
}

思路B

前向星存图

先健了,健完再写。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值