勵志用盡量少的代碼做高效的表達。
題目(提交)鏈接→UVa-12100
題目描述:
我們需要用打印機打印任務。每個任務都有1~9間的優先級,優先級越高,任務越急。
打印機的運作方式:從打印隊列裏取出一個任務j,如果隊列裏有比j更急的任務,則直接把j放到打印隊列尾部,否則打印任務j。每次打印都消耗一分鐘的時間,但調整任務位置不消耗時間。
輸入:
第一行:n個測試用例
第二行:m1(任務個數) m2(我們關注的任務所在位置)
第三行:m1個任務的優先級。
…
輸出:
我們關注的任務完成後的時刻。
舉例:
輸入:
1 1個測試用例
4 2 4個任務,我們關注的任務位於4個任務中的第三個(從第0個開始)
1 2 3 4 4個任務的優先級
分析:
1、隊頭任務1是否爲隊列(1,2,3,4)中優先級最高的? 否,移動到隊列末。此時隊列爲:2 3 4 1,時刻爲0
2、隊頭任務2是否爲隊列(2,3,4,1)中優先級最高的? 否,移動到隊列末。此時隊列爲:3 4 1 2,時刻爲0
3、隊頭任務3是否爲隊列(3,4,1,2)中優先級最高的? 否,移動到隊列末。此時隊列爲:4 1 2 3,時刻爲0
4、隊頭任務4是否爲隊列(4,1,2,3)中優先級最高的? 是,打印任務4。此時隊列變爲:1 2 3,時刻從0變爲1
5、隊頭任務1是否爲隊列(1,2,3)中優先級最高的? 否,移動到隊列末。此時隊列爲:2 3 1,時刻爲1
6、隊頭任務2是否爲隊列(2,3,1)中優先級最高的? 否,移動到隊列末。此時隊列爲:3 1 2,時刻爲1
7、隊頭任務3是否爲隊列(3,1,2)中優先級最高的? 是,打印任務3。時刻從1變爲2。
結束判斷,輸出2。
明白了題意,接下來考慮思路:
思路:
最初的思路:
將m1個任務存入隊列,找到隊列中最大的優先級Max。 出隊,若此任務優先級<Max,則入隊(隊尾)。若等於,且不是我們關注的任務:出隊,T++。
若等於,且是我們關注的任務,T++,輸出T。結束循環。
在實施操作中發現了以下幾個難點:
難點1:如何判斷打印的任務是我們關注的任務?
解決辦法:將每個優先級都+10000,若爲標記任務的優先級,加20000。優先級間相互判斷前做一下取餘。如:10005%10000 = 20005%10000。這種方法叫做自定義標記法。
難點2:最初的想法是在輸入時用Max變量存儲優先級最高的任務, 但如果該任務被打印,Max變動,該怎樣找到當前隊列中優先級最高的任務?
解決辦法:降序優先隊列(priority_queue<int>Max
)存儲優先級,每當優先級最高任務被打印,就出隊一次。
最終的思路:
將m1個任務的優先級做標記後存入隊列q(queue<int>q
),將不做標記的優先級存入降序優先隊列Max(priority_queue<int>Max
)。q出隊,若優先級%10000<Max.top(),則入隊(隊尾), 若優先級%10000=Max.top(),且<20000,q出隊,Max出隊,T++; 若>20000,則輸出T,結束循環。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n; cin >> n; while(n--) {
int m1, m2; cin >> m1 >> m2; //任務數和關注的任務所在位置
int T = 0; //隊列中最大的優先級、時刻
queue<int>q; //主隊列
priority_queue<int>Max; //降序優先隊列,存儲優先級
for(int i = 0; i < m1; i++) {
int x; cin>>x;
Max.push(x); //壓入優先級(Max 中是原本優先級的數)
i == m2 ? x+=20000 : x+= 10000; //將關注任務的優先級做標記
q.push(x); //任務入隊
}
while(1) {
int x = q.front();
q.pop();
if((x%10000) < Max.top()) { q.push(x); } //若不是當前最高優先級,則回隊尾
else
if(x >= 20000) { T++; cout << T << endl; break;} //若是,且爲關注的任務,則輸出,結束循環。
else { Max.pop(); T++; } //若不是關注的任務,則T++, Max出隊,q出隊,T++
}
}
return 0;
}
收穫:
1、才知道隊列是沒有迭代器的。(不要笑話我o(╯□╰)o)
2、自定義標記法做標記