训练计划(第28次CCF计算机软件能力认证)

时间限制: 1.0 秒

空间限制: 512 MiB

下载题目目录(样例文件)

题目背景

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

题目描述

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

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

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

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

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

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

输入格式

从标准输入读入数据。

输入共三行。

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

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

输入的第三行包含空格分隔的 𝑚m 个正整数,其中第 𝑖i 个(1≤𝑖≤𝑚1≤i≤m)数 𝑡𝑖ti​ 表示训练科目 𝑖i 所需天数,满足 1≤𝑡𝑖≤𝑛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解释

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

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

样例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解释

七项科目间的依赖关系如图所示,其中仅科目 55 无法在 1010 天内完成训练。

img

具体来说,科目 55 依赖科目 22、科目 22 又依赖于科目 11,因此科目 55 最早可以从第 44 天开始训练。

样例3输入

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

样例3输出

1 11 21 31 41

子任务

70%70% 的测试数据满足:顿顿无法在 𝑛n 天内完成全部 𝑚m 项科目的训练,此时仅需输出一行“最早开始时间”;

全部的测试数据满足 0<𝑛≤3650<n≤365 且 0<𝑚≤1000<m≤100。

解题思路:

这题前面70分相当简单,重点是后面三十分,我的思路是用一个数组存储每个节点的后继节点,然后要考虑到一个节点同时有多个节点的情况,这个时候该节点最晚开始时间要根据后继节点中最晚开始时间最早的来计算。

#include<iostream>

using namespace std;



int main() {
	int n,m;

	cin>>n>> m;
	int w[m+1][2];
	int s[m+1][2];
	int d[m+1][2];
	int t[m+1][m+1]={0};
	int y[m+1]={0};
	for(int i=1;i<=m;i++) {
		cin >> w[i][0];
		
	}
	
	for(int i=1;i<=m;i++) {
		cin >> w[i][1];	
			
	}
	for(int i=m;i>=1;i--) {
		if(w[i][0]!=0){
			t[w[i][0]][i]=i;
			y[w[i][0]]=n+1;
		}
		
	}
	int flag =0;
	for(int i=1;i<=m;i++){
		if(w[i][0]==0){
			s[i][0]=1;
			d[i][0]=s[i][0]+w[i][1]-1;
		}else{
			s[i][0]=d[w[i][0]][0]+1;
			d[i][0]=s[i][0]+w[i][1]-1;
	
		}
		if(d[i][0]>n){
			flag=1;
		}

		
	}
	if(flag ==1){
		for(int i=1;i<=m;i++){
			cout<<s[i][0]<<" ";
		}
	}else{
		for(int i=1;i<=m;i++){
			cout<<s[i][0]<<" ";
		}
		cout <<endl;
		for(int i=m;i>=1;i--){
			if(y[i]==0){				
				s[i][1]=n-w[i][1]+1;			
			}else {
				for(int j=1;j<=m;j++){
					if(t[i][j]!=0&&s[j][1]<=y[i]){
						y[i]=s[j][1];
					}
				}
				s[i][1]=y[i]-w[i][1];			
			}
			
		}
		for(int i=1;i<=m;i++){
			cout<<s[i][1]<<" ";
		}
	}

	return 0;
}

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值