Contest100000601 - 《算法筆記》6.6小節——C++標準模板庫(STL)介紹->priority_queue的常見用法詳解

問題 A: 任務調度

題目描述

讀入任務調度序列,輸出n個任務適合的一種調度方式。

輸入

輸入包含多組測試數據。

每組第一行輸入一個整數n(n<100000),表示有n個任務。

接下來n行,每行第一個表示前序任務,括號中的任務爲若干個後序任務,表示只有在前序任務完成的情況下,後序任務才能開始。若後序爲NULL則表示無後繼任務。

輸出

輸出調度方式,輸出如果有多種適合的調度方式,請輸出字典序最小的一種。

樣例輸入

4
Task0(Task1,Task2)
Task1(Task3)
Task2(NULL)
Task3(NULL)

樣例輸出

Task0 Task1 Task2 Task3

Note

其實可能學過操作系統這門課的話,能更好的理解這個問題,這個問題考察的就是任務的優先級調度。優先級最高的任務,最先輸出,而在計算機中,優先級通常是用一個整數來表示。所以我們仔細觀察輸入的式子便能有這樣的思路:

分析每一行輸入的字符串,對於前序任務,我們獲取它的優先級,然後將其後所有後序任務的優先級都置爲前序任務的優先值加1(優先值越高優先級越低,在計算機系統中優先值爲0的任務是優先級最高的,後序任務的優先級要低於前序任務,所有優先值要加1)。然後讀取下一行字符串。

具體做法如下:

  1. 設置map映射,其作用在於對任務做一個記錄,除了Task0的value爲0外,只要mp[task] == 0,就說明該任務尚未做記錄,那麼就對其進行一次記錄,即賦一個優先值。
  2. 設置優先隊列,既然涉及到優先級肯定要用到優先隊列。然後設置task結構體,成員變量是name和priority。利用優先隊列,對task結構體進行優先級排序。
  3. 輸入字符串。只需遍歷字符串直到str[i] == '('即可,讀出來的肯定就是前序任務(仔細看題目)。查看一下是否有該前序任務的映射,沒有的話就記錄一下,然後令其入隊(別忘記入隊)。然後獲取其優先值加1,爲其後序任務進行賦值。
  4. 設置循環,同樣的步驟讀出所有後序任務,查看是否有映射,沒有就記錄,將其優先級設爲前面得到的值,令其入隊。重複3、4直到輸入結束,輸出隊列中的元素。

之所以這麼做是邏輯在內的。那輸入樣例舉例:首先讀取到Task0,mp[Task0] == 0,所以給其記錄一下,令其入隊,記錄其優先值爲0,加1得到pri = 1。接着讀到兩個後序任務Task1和Task2,查看一下映射,發現都爲0,所以記錄一下,優先值都給1。同樣的操作便可將Task3的優先值置爲2。所有Task0、Task1、Task2、Task3的優先值分別是0、1、1、2。按順序出隊就行了。

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

struct task // 定義任務結構體
{
    string name;
    int priority; // priority每個任務的優先級,數值越大優先級越大
    friend bool operator < (const task &t1, const task &t2) // 設置結構體優先級
    {
        if (t1.priority != t2.priority)
            return t1.priority > t2.priority; // 優先值小(優先級更高)的排前面,這裏不同於sort
        else
            return t1.name > t2.name; // 字典序小的排前面
    }
};

void CalPriority(string str, priority_queue<task> &q, map<string, int> &mp)
{ // 由輸入的字符串計算並更新對應任務的優先級
    string nametemp;
    task tasktemp;
    int i = 0; // i遍歷字符串str
    while (str[i] != '(') // 讀到左括號退出循環
        nametemp += str[i++]; // 退出循環後temp中存的即爲前序任務
    if (mp[nametemp] == 0) // 如果該任務的優先級仍爲0,說明首次出現
    {
        tasktemp.name = nametemp;
        tasktemp.priority = 0;
        q.push(tasktemp); // 令tasktemp入隊
        mp[nametemp] = 0;
    }
    int pri = mp[nametemp] + 1; // pri保存其優先值並加1
    nametemp = ""; // 重置nametemp

    while (i < str.length())
    {
        while (i < str.length() - 1 && str[i] != '(' && str[i] != ',')// 讀到非數字字母字符終止循環
            nametemp += str[i++]; // 讀到非數字字母字符終止循環
        if (nametemp != "NULL" && nametemp != "" && mp[nametemp] == 0)
        { // temp不爲NULL或空串,且其在mp未記錄過
            tasktemp.name = nametemp;
            tasktemp.priority = pri;
            q.push(tasktemp); // 令tasktemp入隊
            mp[nametemp] = pri;
            nametemp = ""; // 重置nametemp
        }
        ++i; // 防止死循環
    }
}

int main()
{
    int n;
    string str;
    priority_queue<task> q;
    map<string, int> mp;
    while (cin >> n)
    {
        while (n--)
        {
            cin >> str;
            CalPriority(str, q, mp);
        }
        while (q.empty() != true)
        {
            cout << q.top().name; // 輸出隊首元素
            if (q.size() > 1)
                cout << " ";
            else
                cout << endl;
            q.pop(); // 令隊首元素出隊
        }
    }

    return 0;
}

一定要自己寫一遍哦~~~

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