ccf 201709-2 公共钥匙盒

思路

  • 一共有k节课,每节课要借一次和还一次,即借k次、还k次
  • 每节课有开始时间(借)和结束时间(还)
  • 分别对借和还排序,都是按照时间从小到大排序,注意在还时,如果结束时间相同,则按照教室编号从小到大排序
  • 借和还分别,两个计数器分别从1开始遍历k节课,如果当前借操作的时间小于还操作,则进行借操作,如果当前借操作的时间大于还操作,则进行还操作,如果二者相等,则先还再借
  • 借操作:将开始时间等于当前时间的课的钥匙都取出,计数器移到下一个时间点
  • 还操作:将结束时间等于当前时间的课的钥匙依次放入第一个空位置(已经按教室编号从小到大排序过),计数器移到下一个时间点
  • 肯定是借的计数器先遍历完,最后只有还操作,因此只有在借计数器遍历完之前才比较借和还的时间大小,借遍历完之后只有还存在

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n, k, v[1005], v1[1005], v2[1005], no[1005], start[1005], end[1005];
int now_jie, now_huan;  //借、还计数器

bool cmp1(int a, int b)  //借的排序
{
	return start[a] < start[b];
}
bool cmp2(int a, int b)  //还的排序
{
	if(end[a] == end[b]) return no[a] < no[b];
	else return end[a] < end[b];
}

void jie()
{
	int now_time = start[v1[now_jie]];
	//将开始时间等于当前时间的课的钥匙都还了
	for(now_jie; now_jie <= k && (start[v1[now_jie]] == now_time); ++now_jie)
	{
		for(int j = 1; j <= n; ++j)
		{
			if(v[j] == no[v1[now_jie]])
			{
				v[j] = 0;
				break;
			}
		}
	}
	
}
void huan()
{
	int now_time = end[v2[now_huan]];
	//将结束时间等于当前时间的课的钥匙都还了
	for(now_huan; now_huan <=k && end[v2[now_huan]] == now_time; ++now_huan)
	{
		for(int j = 1; j <= n; ++j)
		{
			if(v[j] == 0)
			{
				v[j] = no[v2[now_huan]];
				break;
			}
		}
	}
}
int main()
{
	cin >> n >> k;
	for(int i = 1; i <= n; ++i)
		v[i] = i;
	for(int i = 1; i <= k; ++i)
		v1[i] = v2[i] = i;

	for(int i = 1; i <= k; ++i)
	{
		scanf("%d%d%d", no + i, start + i, end + i);
		end[i] += start[i];  
	}
		
	sort(v1 + 1, v1 + 1 + k, cmp1);  //借
	sort(v2 + 1, v2 + 1 + k, cmp2);  //还
	now_jie = now_huan = 1;
	while(now_jie <= k)
	{
		int u1 = v1[now_jie], u2 = v2[now_huan];
		if(start[u1] < end[u2])
			jie();
		else if(start[u1] >end[u2])
			huan();
		else
		{
			huan();
			jie();	
		}
	}
	while(now_huan <= k)
		huan();
	for(int i = 1; i <= n; ++i)
		printf("%d ", v[i]);
	cout << endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值