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