[CCFwithAxin]201709-2公共鑰匙盒

心情不好刷刷題

CCF/CSP 一個認證考試。。。你懂的。。。

題目

試題編號: 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 ≤ 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。

題解

思路很簡單,把對鑰匙的操作(借/還)看成一個事件,按照時間線順序排列,然後依次執行事件。
需要注意的就是排列時的優先級:時間優先,相同時還優先;兩個還事件按鑰匙的編號,編號小的優先。

代碼如下,因爲只是做題解悶&日常練習C++,所以可讀性優先。
C++11真好用。。。然而lj系統不支持(C++一般版C++11版

C++11版

const int GETKEY = 0;
const int PUTKEY = 1;//事件標誌
//事件
struct Event{
    Event(int eventFlag, int objTime, int objKeyId):flag(eventFlag),time(objTime), keyId(objKeyId){} 
    int flag;  //  借/還
    int time;  //  事件發生的時間
    int keyId; //  涉及的鑰匙id
};
bool compareEvent(const Event &e1, const Event &e2){
    if(e1.time < e2.time)//時間優先級最高
        return true;
    if(e1.time == e2.time){
        if(e1.flag > e2.flag)//時間相同 環事件優先(還爲1哈哈)
            return true;
        if(e1.flag < e2.flag)
            return false;
        if(e1.keyId < e2.keyId)//兩個同時發生的相同類型事件看鑰匙編號
            return true;
        else
            return false;

    }
    return false;
}
int main(void)
{
    vector<Event> taskLine;//時間線
    vector<int> keys;      //鑰匙盒
    int numKey;
    int n ;
    scanf("%d%d",&numKey, &n);
    //初始化鑰匙盒
    for(int i = 0; i <= numKey; i++)
        keys.push_back(i);
    int keyId,getTime,speedTime;
    while(n--){
        scanf("%d%d%d",&keyId, &getTime, &speedTime);
        taskLine.push_back(std::move(Event(GETKEY, getTime, keyId)));//插入借事件
        taskLine.push_back(std::move(Event(PUTKEY, getTime+speedTime, keyId)));//插入還事件,注意這裏的時間是用借時間+用掉的事件
    }
    sort(taskLine.begin(), taskLine.end(), compareEvent);//排序請見上面的函數
//遍歷處理時間線
    for( auto ev : taskLine){
        if(ev.flag == GETKEY){
        //處理借事件,在鑰匙盒裏找到,取出(空位置標誌爲-1)
            auto it = find_if(keys.begin(), keys.end(), [ev](const int keyId){return keyId == ev.keyId;});
            *it = -1;  
        }
        if(ev.flag == PUTKEY){
        //處理還事件,在鑰匙盒裏找空位置,放入鑰匙
            auto it = find_if(keys.begin(), keys.end(), [](const int keyId){return keyId == -1;});
            *it = ev.keyId;
        }
    }
//輸出打印
    for(auto i = keys.begin() + 1; i != keys.end(); ++i)
        printf("%d ",*i);

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