1. 程式人生 > >【貪心】Buaacoding1032 AlvinZH的學霸養成記II

【貪心】Buaacoding1032 AlvinZH的學霸養成記II

AlvinZH的學霸養成記II
時間限制: 1000 ms 記憶體限制: 65536 kb
總通過人數: 63 總提交人數: 91
題目描述
由於校賽簽到題而遲到的養成記II,你注意到了嗎?

AlvinZH妄圖成為一個學霸,他想學很多很多的課。

教務網上的課都太固定了,AlvinZH準備去慕課上選幾門課學習提高一下姿勢。每門課程依然有持續時間 d ,雖然沒有固定開始時間,卻有結課時間 e ,過了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


 猜到是貪心了,然而貪法出錯了,一開始想的是時間方向倒著貪心,每次取本時間點結束的,且起點最晚的課,再把時間指標跳到這個起點,過程中不斷把備選的課程加入按持續時間的小根堆。這樣會出現一個問題,就是每次選走了起點最晚的課,但是這對於剩下的備選的課來說可能造成更壞的情況。
 一組資料,我的答案是2,而正確答案顯然是3,我一開始會選取15 1,把時間指標跳到14,然而剩餘的課程持續的時間就很長,造成錯誤。
3
7 16
1 15
9 20
 正確的貪心是:根據截止時間從小到大排序,用優先佇列記錄當下已選課程,列舉看看能不能上這門課,如果能就加上這個時間,否則,優先佇列裡彈出一個佔用時間最大值,這樣就能滿足課程數最大而當下時間最小了。
 這麼做正確的原因是,如果存在一種方案,那麼把方案中的課程重新按照截止時間從小到大的順序上,一定也是符合條件的(可以用歸納法證明,從兩門課入手)
 貪心還是需要多練習啊多練習

#include<cstdio>
#include<queue>
#include<algorithm>
#define e first
#define d second
using namespace std;

int n,cur,ans;
pair<int,int> a[100005];
priority_queue<int> Q;

int main()
{
	while(scanf("%d",&n)==1)
	{
		for(int i=1;i<=n;i++)
			scanf("%d%d",&a[i].
d,&a[i].e); sort(a+1,a+n+1); cur=ans=0; for(int i=1;i<=n;i++) { ++ans; Q.push(a[i].d); cur+=a[i].d; if(cur>a[i].e) { --ans; cur-=Q.top(); Q.pop(); } } while(!Q.empty()) Q.pop(); printf("%d\n",ans); } return 0; }