CCF CSP 202212-2 训练计划(C++)

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF CSP 202212-2 训练计划(C++)相关的知识,希望对你有一定的参考价值。

CCF CSP 202212-2 训练计划(C++)

问题背景

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

问题描述

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

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

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

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

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

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

输入格式

从标准输入读入数据。

输入共三行。

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

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

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

输出格式

输出到标准输出中。

输出共一行或两行。

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

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

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

样例 1 输入

10 5
0 0 0 0 0
1 2 3 2 10

样例 1 输出

1 1 1 1 1
10 9 8 9 1

样例 1 说明
五项科目间没有依赖关系,都可以从第 1 天就开始训练。

10 天时间恰好可以完成所有科目的训练。其中科目 1 耗时仅 1 天,所以最晚可以拖延到第 10 天再开始训练;而科目 5 耗时 10 天,必须从第 1 天就开始训练。

样例 2 输入

10 7
0 1 0 3 2 3 0
2 1 6 3 10 4 3

样例 2 输出

1 3 1 7 4 7 1

样例 2 说明 七项科目间的依赖关系如图所示,其中仅科目 5 无法在 10 天内完成训练。

具体来说,科目 5 依赖科目 2、科目 2 又依赖于科目 1,因此科目 5 最早可以从第 4 天开始训练。

70分代码
#include<iostream>
using namespace std;
const int N=410;
int f[N];
int a[N];
int early[N];
int n,m;
int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    
        scanf("%d",&f[i]);
    
    for(int i=1;i<=m;i++)
    
        scanf("%d",&a[i]);
    
    for(int i=1;i<=m;i++)
    
        if(!f[i])
        
            early[i]=1;
        
        else
        
            early[i]=early[f[i]]+a[f[i]];
        
    
    for(int i=1;i<=m;i++)
    cout<<early[i]<<" ";
    cout<<endl;


100分代码
#include<iostream>
#include<vector>
using namespace std;
const int N=410;
int f[N];
int a[N];
int early[N];
int late[N];
int n,m;
vector<int>son[N];
int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    
        scanf("%d",&f[i]);
        if(f[i]!=0)
        son[f[i]].push_back(i);
        //记录每个父亲的儿子有哪些
    
    for(int i=1;i<=m;i++)
    
        scanf("%d",&a[i]);
    
    for(int i=1;i<=m;i++)
    
        if(!f[i])
        
            early[i]=1;
        
        else
        
            early[i]=early[f[i]]+a[f[i]];
        
    
    for(int i=1;i<=m;i++)
    cout<<early[i]<<" ";
    cout<<endl;
    for(int i=1;i<=m;i++)
    if(early[i]+a[i]-1>n)
    
        return 0;
    
    //不能完成训练计划
    for(int i=m;i>=1;i--)
    
        vector<int>&t=son[i];
        if(t.size()==0)
        
            late[i]=n-a[i]+1;
        
        //叶结点
        else
        
            int minv=0x3f3f3f3f;
            for(int j=0;j<t.size();j++)
            
                minv=min(minv,late[t[j]]);
            
            late[i]=minv-a[i];
        
    
    //倒着计算掉,笑眯眯
    for(int i=1;i<=m;i++)
    cout<<late[i]<<" ";
    cout<<endl;


#include <bits/stdc++.h>
using namespace std;
struct xl
    int kaishi; //最早开始时间
    int len; //持续时长
    int jieshu; //结束时间(用于判断是否超过了总时长n)
    int yilai; //该项目是否依赖于某个前面的项目
    int tuichi=999; //该项目最早开始时间最多可以推迟多久,即得到最晚开始时间
    bool genggai=false;
    //该项目的推迟时间是否已经被更改过,如果是,说明某一个后面的项目以来该项目,且那个项目已经算出来的最多推迟时间
    //那么该项目的最多推迟时间应该等于后面那个项目的最多推迟时间(不然后面那个项目就超时了)
;
int main()

    int n,m;
    cin>>n>>m;
    xl a[m+1];
    a[0].jieshu=0; //多存一个a[0],这样就不用每次都判断是否有依赖的前一项目
    a[0].yilai=0;
    for(int i=1;i<=m;i++)
    
        cin>>a[i].yilai; //存储每个项目的依赖关系
    
    for(int i=1;i<=m;i++)
    
        cin>>a[i].len; //每个项目时常
    
    bool chaoshi=false;
    for(int i=1;i<=m;i++)
    
        a[i].kaishi=a[a[i].yilai].jieshu+1; //最早开始时间就等于该项目依赖的前一项目的结束时间+1
        a[i].jieshu=a[i].kaishi+a[i].len-1; //最早开始的话,对应的该项目结束时间
        if(a[i].jieshu>n) chaoshi=true; //超时判断
        cout<<a[i].kaishi<<" ";
    
    if(!chaoshi)
    
        cout<<endl;
    for(int i=m;i>=0;i--)
    
        if(!a[i].genggai) 
            a[i].tuichi=n-a[i].jieshu;
        //如果该项目未经过更改,则表明后面没有依赖该项目的其他项目,那么这个项目的最终结束时间就可以定为最后一天
        //那么推迟时间就是最后一天减去预定的最早的结束时间
        if(a[i].yilai!=0) //如果该项目有依赖项目,那么该依赖项目的最多推迟时间等于该项目的推迟时间(否则后面的项目就会超时)
        
            a[a[i].yilai].tuichi = min(a[a[i].yilai].tuichi,a[i].tuichi);//有可能有多个后面的科目都依赖该科目,
            //那么该科目能推迟的最长时间应该是后面所有相关科目的推迟时间的最小值
            //(比如上面例子的图,两个科目都与3有关,那么3能够推迟的时间就应该取4、6两个科目推迟时间的最小值)
            a[a[i].yilai].genggai=true; //标记依赖项目已经过更改,这样循环到依赖项目时就不能再用n-jieshu来计算推迟时长了
        
        
        for(int i=1;i<=m;i++)
        
            cout<<a[i].kaishi+a[i].tuichi<<" ";
        
        
    return 0;

#include<bits/stdc++>
#include<bits/stdc++.h>
using namespace std;

int main() 
    int n, m;
    cin >> n >> m;
    int p[m+1];
    int t[m+1];
    for (int i = 1; i <= m; i++) 
        cin >> p[i];
    
    for (int i = 1; i <= m; i++) 
        cin >> t[i];
    
    int early[m+1];
    int last[m+1];
    for (int i = 1; i <= m; i++) 
        if (p[i] == 0)   // 无依赖
            early[i] = 1;
            last[i] = n-t[i]+1;
         else 
            early[i] = early[p[i]] + t[p[i]];
            last[i] = n-last[p[i]]-t[i];
        
    
    for (int i = 1; i <= ml i++) 
        cout << early[i]  << " " << endl;
    
    int min = 1;
    for (int i = 1; i <= ml i++) 
        if (last[i] < min)
            min = last[i];
    
    if (min > 0) 
        for (int i = 1; i <= ml i++) 
            cout << last[i]  << " " << endl;
        
    

代码来源

Link

Link

以上是关于CCF CSP 202212-2 训练计划(C++)的主要内容,如果未能解决你的问题,请参考以下文章

CCF-CSP 201604 赛题训练

CCF-CSP 201709 赛题训练

CCF-CSP 201712 赛题训练

CCF-CSP 201612 赛题训练

CCF-CSP 201609 赛题训练

CCF-CSP 201909 赛题训练