1017 在銀行排隊 (25分)(優先隊列,新手也能看得懂)

優先隊列保存窗口時間,每次選出最小時間處理

講解

  1. 設置一個將題幹hh:mm:ss時間轉化爲秒爲單位的時間的函數
  2. 利用一個優先隊列(這裏是一個小根堆,每次top爲時間最小的元素)保存每個窗口的當前時間
  3. 將每個人的個人信息用struct保存,包括到達時間和處理時間
  4. 將每個人以到達時間排序(由小到大),先到的先處理
  5. 開始模擬銀行工作:
    1)取出當前時間time_win(就是該窗口上一次處理的結束時間,初始化爲8*3600)最小的銀行窗口,接受最早到達的人的申請
    2)修改當前窗口的結束時間爲time_win + 處理人的執行時間process(這就是該窗口下一次可以接受申請的時間)
    3)將該窗口信息重新入隊,然後循環這三步,代碼中有詳細註釋

算法思路

思路源自於模擬正常銀行工作流程,哪個窗口先空閒哪個窗口工作,符合優先隊列的性質,然後先到的人先安排,所以要排序

代碼部分

代碼中包含了測試輸出語句,方便讀者copy後去測試pat例子,這裏已經註釋掉了,可以直接在pat提交

#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ostream>
#include <queue>

using namespace std;
/** 保存8:00 和 17:00 的秒進制時間 **/
const int Start = 8*3600;
const int End = 17*3600;

/** 建立一個結構體,保存每個人的到達時間和執行時間 **/
struct node{
    int arr_time;
    int pro_time;
    bool operator < (const node& n1)const{
        return this->arr_time < n1.arr_time;
    }
//    friend ostream& operator << (ostream& os,const node& n){
//        os<<n.arr_time<<" "<<n.pro_time<<endl;
//        return os;
//    }
};
vector<node> people;


/** 時間轉化函數 **/
int time_int(string& s){
    string hh = s.substr(0,2),mm = s.substr(3,2),ss = s.substr(6,2);
    int hi = atoi(hh.c_str()),mi= atoi(mm.c_str()),si = atoi(ss.c_str());
    return hi*3600 + mi*60 + si;    //轉換成秒保存
}

int main()
{
    int N,K;
    cin>>N>>K;
    /** 創建一個容量爲K的小根堆,表示k個窗口 **/
    priority_queue<int,vector<int>,greater<int>> pq;
    for(int i=0;i<K;i++) pq.push(Start);

    for(int i=0;i<N;i++){
        string arrive;  // 到達時間
        int process;    // 辦理時間
        cin>>arrive>>process;
        people.push_back({time_int(arrive),process*60});
    }
    sort(people.begin(),people.end());
//    cout<<"start = "<<Start<<endl;
//    cout<<"End = "<<End<<endl;
//    for(int i=0;i<people.size();i++){
//        cout<<people[i];
//    }

    /** 處理每一個人 **/
    double ans = 0;
    int realN = 0;
    for(int i=0;i<N;i++){
        node f = people[i]; // 獲取最先到達的一個人
        if(f.arr_time > End) continue;  // 超時到達不處理
        realN++;
//        cout<<"i = "<<i<<endl;
        int temp_win = pq.top(); // 獲取第一個空閒的窗口
//        cout<<"第一個空閒窗口時間爲:"<<temp_win<<endl;
        pq.pop();


        int arr_time = f.arr_time;
        if(arr_time <= temp_win){       // 到達時沒有空閒窗口,需要等待
            ans += temp_win-arr_time;     // 累計等待時間
            temp_win += f.pro_time;     // 修改當前窗口的下一次空閒時刻
            pq.push(temp_win);
        }else{                          // 到達時有空閒窗口,無需等待直接工作
            temp_win = arr_time + f.pro_time;
            pq.push(temp_win);
        }
    }
    printf("%.1f",ans/realN/60);
    return 0;
}

pat運行結果

在這裏插入圖片描述

複雜度分析

  1. 時間複雜度:對N個人時間排序的時間爲O(NlogN),然後需要對每個人處理一次,還有入隊出隊的處理,處理時間爲O(N),隊列調整時間爲O(log(K)),整體時間複雜度爲O(max(Nlog(N),log(K)));
  2. 空間複雜度:優先隊列複雜度爲O(K),結構體信息複雜度爲O(N),整體複雜度爲O(K+N);

感謝大家觀看!歡迎評論區批評指正。

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