CCF-CSP 202212-1 训练计划
😸题目要求
🐈⬛问题背景
西西艾弗岛荒野求生大赛还有 n n n 天开幕!
🐈⬛问题描述
为了在大赛中取得好成绩,顿顿准备在 n n n 天时间内完成“短跑”、“高中物理”以及“核裂变技术”等总共 m m m 项科目的加强训练。其中第 i i i 项 ( 1 < i ≤ m ) (1 < i \leq m) (1<i≤m)科目编号为 i i i ,也可简称为科目 i i i。已知科目 i i i 耗时 t i t_i ti 天,即如果从第 a a a 天开始训练科目 i i i,那么第 a + t i − 1 a+t_i-1 a+ti−1 天就是该项训练的最后一天。
大部分科目的训练可以同时进行,即顿顿在同一天内可以同时进行多项科目的训练,但部分科目之间也存在着依赖关系。如果科目 i i i 依赖科目 j j j,那么只能在后者训练结束后,科目 i i i 才能开始训练。具体来说,如果科目 j j j 从第 a a a 天训练到第 a + t j − 1 a+t_j-1 a+tj−1 天,那么科目 i i i 最早只能从第 a + t j a+t_j a+tj 天开始训练。还好,顿顿需要训练的 m m m 项科目依赖关系并不复杂,每项科目最多只依赖一项别的科目,且满足依赖科目的编号小于自己。那些没有任何依赖的科目,则可以从第 1 1 1 天就开始训练。
对于每一项科目,试计算:
1)最早开始时间:该科目最早可以于哪一天开始训练?
2)最晚开始时间:在不耽误参赛的前提下( n n n 天内完成所有训练),该科目最晚可以从哪一天开始训练?
n n n 天内完成所有训练,即每一项科目训练的最后一天都要满足 ≤ n \leq n ≤n。需要注意,顿顿如果不能在 n n n 天内完成全部 m m m 项科目的训练,就无法参加大赛。这种情况下也就不需要再计算“最晚开始时间”了。
🐈⬛输入格式
从标准输入读入数据。
输入共三行。
输入的第一行包含空格分隔的两个正整数 n n n 和 m m m,分别表示距离大赛开幕的天数和训练科目的数量。
输入的第二行包含空格分隔的 m m m 个整数,其中第 i i i 个 ( 1 ≤ i ≤ m ) (1 \leq i \leq m) (1≤i≤m) 整数 p i p_i pi 表示科目 i i i 依赖的科目编号,满足 0 ≤ p i < i 0 \leq p_i < i 0≤pi<i; p i = 0 p_i=0 pi=0 表示科目 i i i 无依赖。
输入的第三行包含空格分隔的 m m m 个正整数,其中第 i i i 个 ( 1 ≤ i ≤ m ) (1 \leq i \leq m) (1≤i≤m) 数 t i t_i ti 表示科目 i i i 所需天数,满足 1 ≤ t i ≤ n 1 \leq t_i \leq n 1≤ti≤n。
🐈⬛输出格式
输出到标准输出中。
输出共一行或两行。
输出的第一行包含空格分隔的 m m m 个正整数,依次表示每项科目的最早开始时间。
如果顿顿可以在 n n n 天内完成全部 m m m 项科目的训练,则继续输出第二行,否则输出到此为止。
输出的第二行包含空格分隔的 m 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 天开始训练。
🎶样例3输入
10 5
0 1 2 3 4
10 10 10 10 10
🎶样例3输出
1 11 21 31 41
🐈⬛子任务
70% 的测试数据满足:顿顿无法在
n
n
n 天内完成全部
m
m
m 项科目的训练,此时仅需输出一行“最早开始时间”;
全部的测试数据满足:
0
<
n
≤
365
0 < n \leq 365
0<n≤365 且
0
<
m
≤
100
0 < m \leq 100
0<m≤100。
😸问题解决
🐈满分代码(含逐行代码解释)
🍭C++
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
map<int,int> p, t; //不用map也可以,正常定义数组即可
for (int i = 1; i <= m; i++){
cin >> p[i]; //依赖科目编号
}
for (int i = 1; i <= m; i++){
cin >> t[i]; //训练所需天数
}
int flag = 1; //标记是否能完成全部科目,默认能完成为1,不能完成为0
map<int,int> earliest, latest; //不用map也可以,正常定义数组即可
// 将每个科目的最早时间确定
for (int i = 1; i <= m; i++) {
if (p[i] == 0) //没有依赖的科目
earliest[i] = 1; //最早的时间就是第一天
else
earliest[i] = earliest[p[i]] + t[p[i]]; //否则就是依赖科目的天数加上本身训练所需天数
// 判断所有科目最早开始的情况是否可以完成所有科目
if (earliest[i] + t[i] - 1 > n)
flag = 0;
}
// 输出每项科目的最早开始时间
for (int i = 1; i <= m; i++)
cout << earliest[i] << " ";
cout << endl;
// 判断是否可以完成项目
if (flag == 1) {
// 将确定每个科目的最晚,从最后的科目往前推
for (int i = m; i >= 1; i--) {
int temp = 1000; //假定一个很大的天数
for (int j = i + 1; j <= m; j++) {
if (p[j] == i) // 寻找是否有依赖该科目的科目
temp = min(temp, latest[j]); //有依赖则更新最小训练天数
}
if (temp == 1000) // 如果没有被依赖
latest[i] = n - t[i] + 1; //最晚开始时间 = 最后期限 - 持续时间的时刻
else //如果有被依赖
latest[i] = temp - t[i]; //最晚开始时间 = 依赖它的科目的最晚开始的时刻最小的科目 - 本身的持续时间的时刻
}
// 输出每项科目的最晚开始时间
for (int i = 1; i <= m; i++)
cout << latest[i] << " ";
}
return 0;
}
🐈场景拓展
本题代码可以应用于需要进行任务调度和时间安排的项目管理场景,特别是涉及到任务依赖和时间安排的问题。这段代码主要实现了对每项任务的最早开始时间和最晚开始时间的计算,以及判断是否能够在规定时间内完成所有任务。
- 任务调度和时间安排:给定一组任务,每个任务有其依赖的任务和所需的训练天数,要求确定每个任务的最早开始时间和最晚开始时间,以及判断是否能在规定时间内完成所有任务。
- 项目进度计划:给定一组任务,每个任务有其依赖的任务和所需的训练天数,要求制定一个项目进度计划,确定每个任务的开始时间和截止时间,同时考虑到任务之间的依赖关系和持续时间。
- 课程安排:给定一组课程,每门课程有其先修课程和所需的学习时间,要求确定每门课程的最早开始时间和最晚开始时间,以及判断是否能在规定学习时间内完成所有课程。
- 工作流程管理:给定一组工作流程步骤,每个步骤有其前置步骤和所需的执行时间,要求确定每个步骤的最早开始时间和最晚开始时间,以及判断是否能在规定时间内完成所有步骤。