CCF 201709-2公共钥匙盒(100分 简单粗暴的做法)

版权声明:转载请注明出处,谢谢合作 https://blog.csdn.net/qq_40738840/article/details/85148977

问题描述
  有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
  钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
  每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
  今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
输入格式
  输入的第一行包含两个整数N, K。
  接下来K行,每行三个整数w, s, c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
  保证输入数据满足输入格式,你不用检查数据合法性。
输出格式
  输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。
样例输入
5 2
4 3 3
2 2 7
样例输出
1 4 3 2 5
样例说明
  第一位老师从时刻3开始使用4号教室的钥匙,使用3单位时间,所以在时刻6还钥匙。第二位老师从时刻2开始使用钥匙,使用7单位时间,所以在时刻9还钥匙。
  每个关键时刻后的钥匙状态如下(X表示空):
  时刻2后为1X345;
  时刻3后为1X3X5;
  时刻6后为143X5;
  时刻9后为14325。
样例输入
5 7
1 1 14
3 3 12
1 15 12
2 7 20
3 18 12
4 21 19
5 30 9
样例输出
1 2 3 5 4
评测用例规模与约定
  对于30%的评测用例,1 ≤ N, K ≤ 10, 1 ≤ w ≤ N, 1 ≤ s, c ≤ 30;
  对于60%的评测用例,1 ≤ N, K ≤ 50,1 ≤ w ≤ N,1 ≤ s ≤ 300,1 ≤ c ≤ 50;
  对于所有评测用例,1 ≤ N, K ≤ 1000,1 ≤ w ≤ N,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。

思路

  • 将取、还钥匙抽象为两个事件,根据时间节点将取还事件进行排序,存入队列中。队列中出队一个事件,立即更新钥匙盒状态

注意点

  • 排序过程中其实是有多个关键字。根据题目可知有三种情况需要考虑
  • 1,时间不同,时间小在前
  • 2,时间相同,”还”在 “取” 前
  • 3,时间同时,事件均为还,编号小在前

数据结构

typedef struct 
{
	int w,s,c;//编号,开始时间,持续时间 
}TIME;//存储输入信息

typedef struct
{
	int id,time;//编号 ,时间 
	bool btaking;//true:还,false:取 
}Event;//按时间来存储还取事件 

算法思想

1, 将所有取还事件按照时间排序,并进入队列

  • 1.1, 升序排序规则:
  • 1.1.1,时间不同,时间小在前
  • 1.1.2,时间相同,”还”在 “取” 前
  • 1.1.3,时间同时,事件均为还,编号小在前

2, 队列非空,出队一个事件,若该事件为取,则遍历钥匙盒数组找到相应钥匙的下标,赋为-1,代表空;否则从将钥匙放入第一个非空位置。直至队列为空,循环结束

3, 输出钥匙状态即可

时间复杂度

T(n) = O(n*n) n为事件个数

心得体会

  • 最近有点迷,可能是膨胀了,今后必须将思路捋清,先知道人会怎么做,再设计数据结构,算法,二者皆有了清晰眉目后,才可以打开电脑编程,效率会高许多,否则,极容易忽略条件并出大大大Bug。谨记!!!!
  • 审题需细心,此题一开始忽略了排序中 同时还事件 应按照钥匙大小排序
  • STL模板的使用,队列队头是front(),栈才是top()
  • 最近可能是事情有点多,忙得迷失方向,有些浮躁,精神状态也不好,心态需调整,锻炼需跟上,身体才是立身之本;不仅身体要健康,精神更为重要,所以得守住自己内心的一亩三分地,嘎油呀,小伙子!

满分C++代码(详细注释)

#include<iostream>
using namespace std;
#include<queue>

typedef struct 
{
	int w,s,c;//编号,开始时间,持续时间 
}TIME;

typedef struct
{
	int id,time;//编号 ,时间 
	
	bool btaking;//true:还,false:取 
}Event;//按时间来存储还取事件 

//模拟函数 
void Cal(TIME t[],int n, int k)
{
	queue<Event> Q;//队列存储排序后的事件 
	
	int key[n+1];//模拟钥匙放置状态 
	
	Event event[2*k+1];//拼接取还事件 
	
	//===================初始化所有取还事件================= 
	for(int i = 0; i < 2*k; i+=2)
	{
		event[i].id = t[(i+1)/2].w;
		
		event[i].time = t[(i+1)/2].s;
		
		event[i].btaking = false;//取 
	}
	
	for(int i = 1; i < 2*k; i+=2)
	{
		event[i].id = t[i/2].w;
		
		event[i].time = t[i/2].s + t[i/2].c;
		
		event[i].btaking = true;//还 
	}
/*	cout<<endl;
	for(int i = 0; i < 2*k; i++)
	{
		cout<<event[i].id<<" "<<event[i].time<<" "<<event[i].btaking<<" "<<endl;
	}
*/	
	//===================对事件按照时间排序,同时入队======================
	//1,时间小在前;2,时间相同,”还”在 “取” 前  3,同时还,编号小在前 
	for(int i = 0; i < 2*k; i++)//冒泡排序 
	{
		for(int j = i + 1; j < 2*k; j++)
		{
			//分别对应条件1,2,3 
			if(event[i].time > event[j].time 
			||(event[i].time == event[j].time && !event[i].btaking && event[j].btaking)
			||(event[i].time == event[j].time && event[i].btaking && event[j].btaking && event[i].id > event[j].id)) 
			{
				int tmp;
				bool tp;
				tmp = event[i].id; event[i].id = event[j].id; event[j].id = tmp;
				
				tmp = event[i].time; event[i].time = event[j].time; event[j].time = tmp;
				
				tp = event[i].btaking; event[i].btaking = event[j].btaking; event[j].btaking = tp;
			}
		}
		
		Q.push(event[i]);//事件入队 
	}
/*	int m = qin.size();
    for(int i = 0; i < m; i++)
    {
    	cout<<qin.front()<<" ";qin.pop();
	}
	cout<<endl;
	for(int i = 0; i < m; i++)
    {
    	cout<<qout.front()<<" ";qout.pop();
	}
*/	
	for(int i = 1; i < n + 1; i++)//钥匙盒初始化 
	{
		key[i] = i;
	}
	
	//=============根据队列中的事件顺序,依次更新钥匙盒状态========================== 
	while(!Q.empty())
	{//cout<<"!!!" <<endl;
		if(Q.front().btaking)//还 
		{
			for(int i = 1; i < n + 1; i++)//从头找到第一个空位,填入 
			{
				if(key[i] == -1)
				{
					key[i] = Q.front().id;// cout<<key[i]<<endl;
					
					Q.pop();
					
					break;
				}
			}
		}
		else//取 
		{
			for(int i = 1; i < n + 1; i++)
			{
				if(key[i] == Q.front().id)//找到相应钥匙位置,取出 。-1表示空 
				{//cout<<"in:"<<key[i]<<endl;
					key[i] = -1;
					
					Q.pop();
					
					break;
				}
			}
		}
	}
	
	
	for(int i = 1; i < n + 1; i++)//输出 
	{
		cout<<key[i]<<" ";
	}
} 
int main()
{
	int n,k;
		
	cin>>n>>k;
	
	TIME t[k];

	for(int i = 0; i < k; i++)
	{
		cin>>t[i].w>>t[i].s>>t[i].c;
	}
	
/*	for(int i = 0; i < k; i++)
	{
		cout<<t[i].w<<" "<<t[i].s<<" "<<t[i].c;
	}
	*/
	
	Cal(t,n,k);
	
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/85148977