20221202 训练计划 CSP真题

20221202 训练计划思路

1. 计算最早开始时间

这一步比较简单
+ 对于没有依赖(即p[i]=0),f[i]=1,最早从第一天开始
+ 有依赖f[i]=f[p[i]]+t[p[i]]    依赖项目的最早+依赖的项目所需要的天数 ==(这里不需要减一,减一是依赖项目完成的时间)==

在处理最早时间的时候可以顺带判断训练是否能够在n天内完成

l[i] = n - ( f[i] + t[i]- 1 ) + 1; //项目最早开始时间+完成天数如果大于n则完不成
// f[i]+t[i]-1 是项目最早开始完成的时间 n - ~ + 1 加一是因为开始时间已经算训练了一天
if(l[i]<1) flag=1;

下面的操作是能够在n天完成的情况进行

2. 计算项目最晚的时间

首先要排序,数据结构是四元组,以项目依赖p升序排列

    struct task{
	int i;  //项目标号
	int p;  //项目依赖
	int t;  //项目时间
	int l;  //项目最晚开始时间
   }a[N];

逆序倒着操作,这样每次计算的项目都只会被后面依赖

  • 对于有依赖或既无依赖也无被依赖的项目, 在项目完成的时刻为n即可 ,
    l[i] = n - t[i] + 1
  • 被依赖的项目,求出依赖项目的最晚时间的最前一个(Min(l[k]),为了保证所有项目能够在n天内完成,需要求得最晚的最早的时间)再减去自己需要的天数
    l[i] = Min ( l[k] ) - t[i]
  • 有依赖且被依赖,本来需要考虑最晚开始时间是否大于依赖项目最晚结束时间,但是项目已经能够在n天内完成,就不需要考虑有依赖这一属性,只需要考虑被依赖这一情况。所以就归结到第二类处理

3. 最后一步,按项目序号排序即可

完整代码

#include<bits/stdc++.h>
const int N=110;
using namespace std;
int f[N],l[N];//f是最早开始的天数从1开始
struct task{
	int i;
	int p;
	int t;
	int l;
}a[N];
bool cmp(task &a,task &b)
{
	return a.p<b.p;
}
bool cmp1(task &a,task &b)
{
	return a.i<b.i;
}
int main()
{
	int j,n,m,i,t[N],p[N],flag=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) scanf("%d",&p[i]);//依赖的项目
	for(i=1;i<=m;i++) scanf("%d",&t[i]);//所需天数
	for(i=1;i<=m;i++)
	{
		//不依赖任何项目
		if(p[i]==0) 
		{
			f[i]=1;
			//要分情况,优先级更高的是训练能够在n天内完成
			l[i]=n-t[i]+1;
		}
		//依赖
		else
		{
			int x,d=0;
			x=p[i];
			//求依赖前面所需要的时间
			f[i]=f[p[i]]+t[p[i]];
			l[i] = n - ( f[i] - 1 + t[i] ) + 1;
			if(l[i]<1) flag=1;
			l[i]=n-t[i]+1;
		}
	}
	for(i=1;i<=m;i++)
	{
		printf("%d ",f[i]);
	}
	printf("\n");
	if(!flag)
	{
		for(int i=1;i<=m;i++)
		{
			a[i].i=i;
			a[i].p=p[i];
			a[i].t=t[i];
			a[i].l=l[i];
		}
		sort(a+1,a+m+1,cmp);
		//更新l数组,使得训练能够在N天完成
		//只需要更新p[i]=0.p[i]>0时已计算
		//找到以自己为依赖 l 的最小值
		for(int i=m;i>=0;i--)
		{
			int min=366;
			for(int j=i+1;j<=m;j++)
			{
				if( a[j].p==a[i].i && min>a[j].l )  
				{
					min=a[j].l;
				}
				if(a[j].p>a[i].i) break;
			}
			if(min<366) //若存在依赖
			{
				a[i].l=min-a[i].t;
			}
		}
		sort(a+1,a+m+1,cmp1);
		for(i=1;i<=m;i++)
		printf("%d ",a[i].l);
		printf("\n");
	}
	return 0;
}

软微圣经

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值