AlvinZH的學霸養成記II——1032
阿新 • • 發佈:2018-12-14
AlvinZH的學霸養成記II
時間限制:1000ms 記憶體限制:65536kb
題目描述
由於校賽簽到題而遲到的養成記II,你注意到了嗎?
AlvinZH妄圖成為一個學霸,他想學很多很多的課。
教務網上的課都太固定了,AlvinZH準備去慕課上選幾門課學習提高一下姿勢。每門課程依然有持續時間 dd ,雖然沒有固定開始時間,卻有結課時間 ee ,過了DDL後不可再學習此課程。AlvinZH只有在連續學習完一門課後,才會開始下一門課的學習,AlvinZH必須得在結課之前完成每門課的學習。
AlvinZH想知道他最多能學習多少門課,你來幫幫他吧!
注:AlvinZH最早可以從第一天開始學習,結課時間e代表將在第e天結課。
輸入
輸入包含多組資料。
每組資料第一行為課程數n(0<n≤10^5)。
接下來n行,每行兩個整數d和e,代表課程持續時間和結課DDL(0<d,e≤10^6)。
輸出
對於每組資料,輸出一行,為AlvinZH最多可學習的課程數。
輸入樣例
3
1 1
2 2
3 3
輸出樣例
1
HINT
你想到優先隊列了嗎?
HINT2
可參考Leetcode 630. Course Schedule III
題目分析
考慮到這裡有分別的結束限制,很直觀想法是結束時間靠前的先處理。所以,按照DDL排序,按序處理每門課。
這時候考慮,某個結束時間靠前的在某個DDL之前放可能是憂的,但是他可能影響DDL靠後的課程的放置導致之後不優。但是,對於當前處理的DDL,顯然放置的科目都是DDL更靠前的。所以刪除之前的課並不影響結果。
思考到這步結果就出來了,對於某個課的DDL,假設前一個的最多放置方案用了Tot的時間,當前課需要c,如果Tot+c<=DDL則直接放置,否則選出曾經放置的時間最長的課,對比當前的課:如果當前課的代價小,則刪除選出的課,放進當前的課;否則不變。二叉堆維護即可。
具體思路
貪心+優先佇列優化
設定st為當前時間
按結束時間e排序,依次選擇,並將持續時間d入隊,更新st,若st>e則說明無法安排這門課,但此時不是將該門課出隊,而是將佇列內d最長的課出隊(易知能保證出隊後st<e,且能使st更小,因此這樣做是合理的).
出現的問題:一開始優先佇列的型別建的結構體的,覺得邏輯和實現都沒問題,但就一直WA。換了一種寫法,用int的優先佇列就過了。然而兩種寫法貪心部分的邏輯是一樣的,初步判定問題在於sort或優先佇列的實現上,最後發現sort時比較的是結構體的e參量,而優先佇列中比較的是d參量,wa的程式碼只用e的關係過載了結構體的<符,增加了cmp後過了
AC程式碼
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 struct Lesson{ 7 int d,e; 8 bool operator < (const Lesson &a) const{ //過載<,l1<l2為真當且僅當l1.e<l2.e,此時優先佇列生成最大堆 9 return d<a.d; 10 } 11 }; 12 bool cmp(Lesson l1,Lesson l2){ 13 return l1.e<l2.e; 14 } 15 const int maxn=100007; 16 priority_queue<Lesson> q; 17 Lesson l[maxn]; 18 int main(){ 19 int n; 20 while(~scanf("%d",&n)){ 21 int st=0; 22 for(int i=0;i<n;++i){ 23 scanf("%d%d",&l[i].d,&l[i].e); 24 } 25 sort(l,l+n,cmp); 26 while(!q.empty()) q.pop(); 27 for(int i=0;i<n;++i){ 28 st+=l[i].d; 29 q.push(l[i]); 30 if(st>l[i].e){ 31 st-=q.top().d; 32 q.pop(); 33 } 34 } 35 printf("%d\n",q.size()); 36 } 37 }