CCF-CSP真题202212-2《训练计划》(哈希表)

问题背景

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

问题描述

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

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

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

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

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

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

输入格式

从标准输入读入数据。

输入共三行。

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

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

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

输出格式

输出到标准输出中。

输出共一行或两行。

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

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

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

样例 1 输入

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

样例 1 输出

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

样例 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 天内完成全部 m 项科目的训练,此时仅需输出一行“最早开始时间”;

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

思路:思路都写在了代码注释里!!!

代码实现:

#include<iostream>
#include<map>
#include<vector>

using namespace std;

int main() {
	int n, m;
	map<int, int>maps;        //有序哈希表存储第i项科目依赖的科目
	cin >> n >> m;
	vector<int>days;          //存储训练第i项科目需要天数
	vector<int>prime;         //存储最早开始时间
	vector<int>last(101,n);   //存储最晚开始时间,默认假设m(数据格式m最大值为101)项科目都是最晚(n天)开始的。长度为101,
	bool flag = true;         //标记是否能在n天内完成全部m项科目的训练
	for (int i = 0; i < m; ++i) {  //科目编号为key,从0开始。依赖科目编号为value,value为-1表示没有依赖
		int j;
		cin >> j;
		maps[i] = j - 1;
	}
	for (int i = 0; i < m; ++i) {   //训练第i项科目需要的天数
		int j;
		cin >> j;
		days.push_back(j);
	}
	for (int i = 0; i < m; ++i) {   //从前往后记录每项科目的最早开始时间
		if (maps[i] == -1)          //没有依赖的项目最早开始时间就是第一天
			prime.push_back(1);
		else {                      //有依赖的项目最早开始时间为依赖项目的最早开始时间+完成依赖项目需要的时间
			int day = prime[maps[i]] + days[maps[i]];
			prime.push_back(day);
			if (day + days[i] > n)   //当前项目的最早开始时间+它完成时间超过n天,表明不能在比赛开始前完成训练,标记标志位为false
				flag = false;
		}
	}
	for (int i = 0; i < prime.size(); ++i)  //输出最早开始时间
		cout << prime[i] << " ";
	cout << endl;
	if (flag) {                       //比赛开始前可以完成项目训练
		for (int i = m - 1; i >= 0; --i) {   //从后往前记录最晚开始时间
			last[i] -= days[i];              //最晚也要完成当前项目的训练时间,用暂定最晚开始时间减去当前项目的训练时间
			int day = last[i];               //定义变量day记录当前项目最晚开始时间
			/*
				!!!!!!!!!!!重点!!!!!!!!!!!

				由于被依赖项目的最晚开始时间受依赖它的项目的最晚开始时间影响
				因此若一个项目有依赖项目(依赖项目编号一定在它前面),
				则其依赖项目的最晚开始时间至少和它的最晚开始时间一样。
				所以一个项目有依赖,更新被依赖项目最晚开始时间((暂定,不考虑自身的训练时间))和它的一样。
				
				此时会遇到一个问题:有两个项目依赖同一个项目。
				解决办法:首先这两个项目之间不可能存在依赖关系,它俩可以并行训练。
						被依赖项目的最晚开始时间(暂定,不考虑自身的训练时间)此时取决于这两个项目哪一个的训练时间长,
						也就是让被赖项目的最晚开始时间(暂定,不考虑自身的训练时间)尽可能的小。
				举个例子
						假设被依赖项目x完成自身训练需要1天  刚开始默认所有项目最晚开始时间为20
						有两个项目a,b依赖x,b的编号大于a。a,b两个项目的完成自身训练需要4、3天,则最晚开始时间为16,17天。
						从后往前遍历,x最先受b影响,17<20,x最晚开始时间为17,接着又受a影响,16<17,x最晚开始时间为16。
			*/
			if (maps[i] != -1) {
				last[maps[i]] = day > last[maps[i]] ? last[maps[i]] : day;  //maps[i]表示被依赖项目编号。last[maps[i]]表示被依赖项目最晚开始时间
			}
		}
		for (int i = 0; i < m; i++)   //输出最晚开始时间,由于上一步相减操作中没有考虑多减一天的影响,输出的时候加上这一天
		{
			cout << last[i] + 1 << " ";
		}
		cout << endl;
	}
	
}
  • 38
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[3\]的信息,我们可以得知顿顿需要在n时间完成m项科目的加强训练。每项科目有一个编号,编号为i,其1≤i≤m。每项科目的训练时间为ti,即从第a开始训练科目i,训练将持续到第a+ti−1。科目之间存在依赖关系,如果科目i依赖科目j,那么只能在科目j训练结束后,科目i才能开始训练。 对于csp202212-2题目c++训练计划,我们需要知道c++训练的编号以及训练时间。根据题目描述,我们可以得知c++训练的编号为2。然而,题目没有提供c++训练的具体时间。因此,我们无法确定c++训练时间。 综上所述,我们无法确定c++训练的具体计划。 #### 引用[.reference_title] - *1* *3* [CCF CSP 202212-2 训练计划C++)](https://blog.csdn.net/qq_46092061/article/details/129207826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [CCF-CSP真题202212-2 训练计划》思路+python题解](https://blog.csdn.net/weixin_53919192/article/details/129084465)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值