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

試題編號: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);
                }
                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.)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章