【csp202212-2】训练计划(c++100)

问题背景

西西艾弗岛荒野求生大赛还有 天开幕!

问题描述

为了在大赛中取得好成绩,顿顿准备在 天时间内完成“短跑”、“高中物理”以及“核裂变技术”等总共 项科目的加强训练。其中第 项(1≤�≤�)科目编号为 ,也可简称为科目 。已知科目 耗时 �� 天,即如果从第 天开始训练科目 ,那么第 �+��−1 天就是该项训练的最后一天。

大部分科目的训练可以同时进行,即顿顿在同一天内可以同时进行多项科目的训练,但部分科目之间也存在着依赖关系。如果科目 依赖科目 ,那么只能在后者训练结束后,科目 才能开始训练。具体来说,如果科目 从第 天训练到第 �+��−1 天,那么科目 最早只能从第 �+�� 天开始训练。还好,顿顿需要训练的 项科目依赖关系并不复杂,每项科目最多只依赖一项别的科目,且满足依赖科目的编号小于自己。那些没有任何依赖的科目,则可以从第 1 天就开始训练。

对于每一项科目,试计算:

1)最早开始时间:该科目最早可以于哪一天开始训练?

2)最晚开始时间:在不耽误参赛的前提下( 天内完成所有训练),该科目最晚可以从哪一天开始训练?

天内完成所有训练,即每一项科目训练的最后一天都要满足 ≤�。需要注意,顿顿如果不能在 天内完成全部 项科目的训练,就无法参加大赛。这种情况下也就不需要再计算“最晚开始时间”了。

输入格式

从标准输入读入数据。

输入共三行。

输入的第一行包含空格分隔的两个正整数 ,分别表示距离大赛开幕的天数和训练科目的数量。

输入的第二行包含空格分隔的 个整数,其中第 个(1≤�≤�)整数 �� 表示科目 依赖的科目编号,满足 0≤��<���=0 表示科目 无依赖。

输入的第三行包含空格分隔的 个正整数,其中第 个(1≤�≤�)数 �� 表示训练科目 所需天数,满足 1≤��≤�

输出格式

输出到标准输出中。

输出共一行或两行。

输出的第一行包含空格分隔的 个正整数,依次表示每项科目的最早开始时间。

如果顿顿可以在 天内完成全部 项科目的训练,则继续输出第二行,否则输出到此为止。

输出的第二行包含空格分隔的 个正整数,依次表示每项科目的最晚开始时间。

这道题一反常态,有点太简单了哈哈,不太适应。作为考试前的最后一道第二题练习,记录一下。

这道题基础70分没问题的。

一个训练的开始时间只和它是否需要依赖有关。依赖,则开始时间在被依赖项的开始时间上加上被依赖项的练习时间;不依赖,则开始时间为1。其中如果开始时间+练习时间>n,则说明不能在时间内完成,只需要输出开始时间。

一个训练的最迟开始时间:如果不依赖,则为距离大赛开幕的天数n+1-练习时间。

但是如果依赖呢?

首先,题目中说0<=pi<i,意味着整体结构是很多棵树,如果依赖,则成为被依赖项的叶子结点之一。注意这个之一,这意味着一棵树可能有0个或多个叶子结点。

一个结点一旦有叶子结点,意味着它的最迟开始时间需要提前,提前的时间则为叶子结点中最长需要花费的时间。

这么解释吧,如果这个叶子结点下没有叶子结点,则这个叶子结点需要花费的最长时间就是它本身的练习时间。递推上它的父结点,父结点需要花费的时间就是父结点的练习时间+其子结点中需要花费的最长时间。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct p{
    int s=0;
    int e=0;
    int d;
};
int main(){
    int n,m;
    cin>>n>>m;
    int flag=0;
    p p_s[m+1];
    int days[m+1];
    int tempday[m+1];
    for(int i=1;i<=m;++i){
        cin>>p_s[i].d;
    }
    for(int i=1;i<=m;++i){
        cin>>tempday[i];
        days[i]=0;
    }
    //对于被依赖的项,最晚完成的时间需要提前,现在的问题是提前多少。
    //从叶节点入手,选取完成时间最长的叶节点为提前的时间。
    //由于0<=pi<i,所以回溯
    for(int i=m;i>=1;--i){
        days[i]+=tempday[i];
        if(p_s[i].d!=0){
            days[p_s[i].d]=max(days[i],days[p_s[i].d]);
        }
    }
    for(int i=1;i<=m;++i){
        p_s[i].e=n-days[i]+1;
        if(p_s[i].d==0){
            p_s[i].s=1;
        }
        else{
            p_s[i].s=p_s[p_s[i].d].s+tempday[p_s[i].d];
            if(p_s[i].s+tempday[i]>n){
                flag=1;
            }
        }
    }
    for(int i=1;i<=m;++i){
        cout<<p_s[i].s<<" ";
    }
    cout<<endl;
    if(flag==0){
        for(int i=1;i<=m;++i){
        cout<<p_s[i].e<<" ";
    }
    }cout<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值