您的位置:首页 > 其它

【CCF CSP】 201709-2 公共钥匙盒(100分)

2018-02-10 15:18 381 查看
试题编号:201709-2
试题名称:公共钥匙盒
时间限制:1.0s
内存限制:256.0MB
问题描述:问题描述  有一个学校的老师共用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 ≤ wN, 1 ≤ s, c ≤ 30;

  对于60%的评测用例,1 ≤ N, K ≤ 50,1 ≤ wN,1 ≤ s ≤ 300,1 ≤ c ≤ 50;

  对于所有评测用例,1 ≤ N, K ≤ 1000,1 ≤ wN,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。

解析

题目的核心是把每一个上下课表示成两个取放钥匙的动作,然后对动作进行排序。

首先根据时间的先后排序。

时间相同,根据取放排序,先放后取。

时间相同,是相同的操作,先房间号低的操作。

具体来说,需要构建一个Teacher对象,同时定义operator<方法。

代码

C++

#include <iostream>
#include<algorithm>
#include<vector>
#define MAX_NUMBER 1001
using namespace std;

//上课老师对象
class Teacher{
public:
int id;
int star_time;
int end_time;
};

//上课列表的排序规则
bool compareA(const Teacher &a, const Teacher &b)
{
//开始时间从小到大排序
if(a.star_time<b.star_time)
return true;
//开始时间相同,则按结束时间从小到大排序
else if(a.star_time==b.star_time&&a.end_time<b.end_time)
return true;
else
return false;
}

//使用列表的排序规则
bool compareB(const Teacher &a,const Teacher &b)
{
//结束时间从小到大排序
if(a.end_time<b.end_time)
return true;
//结束时间相等,则按id排序
else if(a.end_time==b.end_time&&a.id<b.id)
return true;
else
return false;
}

int main(int argc, char** argv) {
int n,k;
int key_box[MAX_NUMBER];
vector<Teacher> teachers;
vector<Teacher> use_key;
Teacher temp;
cin>>n>>k;
int max_time = 0;
int min_time = 10100;
//初始化钥匙数组
for(int i=1;i<=MAX_NUMBER;i++)
key_box[i]=i;
//输入数据
for(int i=0;i<k;i++)
{
cin>>temp.id>>temp.star_time>>temp.end_time;
temp.end_time=temp.star_time+temp.end_time;
//得到最大最小范围
temp.end_time>max_time?max_time=temp.end_time:0;
temp.star_time<min_time?min_time=temp.star_time:0;
teachers.push_back(temp);
}
//排序
stable_sort(teachers.begin(), teachers.end(), compareA);
//一个循环一个时间单位
for(int j=min_time;j<=max_time;j++)
{
//cout<<"teachers:"<<teachers.size()<<" use_key:"<<use_key.size();

//使用列表按结束时间,id排序
stable_sort(use_key.begin(),use_key.end(),compareB);

//如果当前使用列表不为空,则开始还钥匙
if(use_key.size()!=0&&use_key.front().end_time==j)
{
//遍历要还的钥匙
for(vector<Teacher>::iterator it=use_key.begin();it!=use_key.end();)
{
//如果有要还的钥匙
if(it->end_time==j)
{
//找到最靠坐边的空位,放钥匙
for(int k=1;k<=n;k++)
{
if(key_box[k]==-1)
{
key_box[k]=it->id;
break;
}
}
//删除元素,返回值指向已删除元素的下一个位置
it=use_key.erase(it);
}
c703

else{//如果没有要还的钥匙
//退出遍历
break;
}
}
}

//遍历当前时间要拿的钥匙
for(vector<Teacher>::iterator it=teachers.begin();teachers.size()!=0;)
{
//如果有要拿的钥匙
if(it->star_time==j)
{
//标注拿走钥匙
for(int i=1;i<=n;i++)
if(key_box[i]==it->id)
key_box[i]=-1;
//添加到使用列表
use_key.push_back(*it);
//移除当前列
it=teachers.erase(it);
}else{//如果没有要拿的钥匙
//退出遍历
break;
}

}
}

//输出结果
for(int i=1;i<=n;i++)
{
if (i == n)
cout << key_box[i];
else
cout << key_box[i] << " ";
}
return 0;
}


备注:

1.std::vector::erase()

函数原型:iterator erase (iterator position);   //删除指定元素

     iterator erase (iterator first, iterator last);  //删除指定范围内的元素

返回值:指向删除元素(或范围)的下一个元素。(An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: