CSP简单题记录

95 阅读4分钟

可能是对于其他人来说算是简单题,但是很明显的是我独自做出它来真的是不容易的,我比较笨。

今天做得一道题的编号是:202212-2,如果大家想要查看的话可以自己去官网上面找到题目来做一下再来看。

由于是第二题,所以基本上都不会超出时间还有内存的限制。

题目具体什么东西由于受到版权保护,这里我就不放出来的。但我把官网的链接放出来:中国计算机学会 (ccf.org.cn)

题目当中说要安排大赛科目的时间,有一些科目之间存在依赖的关系。当然为了简化题目难度,设置每个科目只依赖一个别的科目,并且只依赖科目标号小于自己的。同时如果没有依赖,科目可以同一天开始训练,不限定数目。

现在让我们计算最早和最晚的开始时间,有的情况因为依赖的原因,可能没有最晚开始时间,因为完不成任务。

我先把我的代码贴出来,很垃圾我知道,不过我欣然接纳现在的笨笨的我。

#include<iostream>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int flag=0;
    int base[m+1],need[m+1];
    int fina[m+1],finb[m+1],finc[m+1];//依赖完成所需要的时间
    for(int i=1;i<=m;i++){
        base[i]=0;
        need[i]=0;
        fina[i]=0;
        finb[i]=0;
        finc[i]=0;
        cin>>base[i];
    }
    for(int i=1;i<=m;i++){
        cin>>need[i];
    }
    for (int i = 1; i <= m; i++)
    {
        fina[i]=base[i];
       while(1){
        if(fina[i]==0){
            break;
        }
        else{
            finb[i]+=need[fina[i]];
            fina[i]=base[fina[i]];//一直轮换,往前面的那个依赖前进。
        }
       } 
    }
    for(int i=1;i<=m-1;i++){
        cout<<finb[i]+1<<" ";
        if(finb[i]+need[i]>n){
            flag=1;
        }
        finb[i]=0;
    }
    cout<<finb[m]+1<<endl;
    if(flag==1){
        return 0;
    }
    for(int i=m;i>=1;i--){
        fina[i]=base[i];
        finb[i]=need[i];
        while(1){
            if(fina[i]==0){
                break;
            }
            else{
                if(finc[fina[i]]<finb[i]){
                finc[fina[i]]=finb[i];}
                finb[i]+=need[fina[i]];
            fina[i]=base[fina[i]];
            }
        }
    }
    for(int i=1;i<=m-1;i++){
        cout<<n-finc[i]-need[i]+1<<" ";
    }
    cout<<n-finc[m]-need[m]+1;
    return 0;
}

因为是写题目,自己看懂就行,没有在乎注释,现在讲一下我愚钝的思路。

首先分出大致的目的,我首先需要完成最早开始时间的计算,那么由于存在依赖关系,有些科目不能在第一天开始训练。那我们就要确定下来,那些科目到底被前置的科目拖了多久?也就是前面影响当前科目的依赖需要的总天数。

这里我使用到了循环,因为科目是只能知道需要什么科目,但是不知道一共这总的依赖链到底多长,所以我就使用到了while死循环,当满足前面没有前置科目跳出循环。

为了保护原有的数据不被修改,创建其他的变量来存放中间数据,由于c++语言并不会对初始化的变量赋初值,完全是随机的,所以我们还要手动的赋上所需要的初值。

抱怨一下,我用vscode写c++代码,弄环境搞编译器路径之类的花了我一上午,真的是费劲,还是我太笨了,还挺生气,放轻松。

在循环的时候是从前面向后面进行循环,其实反过来我觉得也是可以的,具体场景没有考虑。对于循环的每一个元素,都会向前寻找到最前的那个依赖,因为有可能依赖会连成一串。

因为是一个科目只会依赖一个前面的科目,那就不需要比较到底哪个依赖比较耗时间长,一次循环下来把前面科目依赖需要的时间相加储存起来,然后及时打印出来,之后这些变量还要参与后面的运算,所以可以在适当位置给它们赋予零值或者你想要的初始值。

后面要计算的是最晚可以什么时候学,因为不一定能够在这些时间学上,所以有的情况判断一下到底要不要进行这种运算,不进行直接返回就可以了。

我个人认为后面这个计算比较复杂,主要总结一下难点:如果从前面还是循环查找,那因为使用的不是链表并没有进行储存数据,很明显不行。还有就是相关的储存问题,我计算出来的依赖所需要的时间因为只有这个长依赖链(如果有)的那里可以往前找到所有的所需时间,所以要在循环一开始就把每一个科目后置科目所需时间赋值给一个变量里面储存起来,当逐渐想前面走的时候可能会找到这个长依赖链的中间位置的节点,那这个算出来的肯定就是相对来说短的时间,通过比较来舍弃掉储存这样的值。这里面还有另外的一个问题,就是可能两个科目会依赖相同的前面的某个科目,这个时候还需要比较哪个长就保留哪一个,因为长的会包容短的时间,毕竟那两个科目没有关系可以一起执行。

我个人觉得这样就没有问题了,当然也说不好,本人愚钝,欣然接受。

image-20230827172137340