【貪心】家庭作業
題目描述
老師在開學第一天就把所有作業都佈置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為10,要求在6天內交,那麼要想拿到這10學分,就必須在第6天結束前交。
每個作業的完成時間都是隻有一天。例如,假設有7次作業的學分和完成時間如下:
老師在開學第一天就把所有作業都佈置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為10,要求在6天內交,那麼要想拿到這10學分,就必須在第6天結束前交。
每個作業的完成時間都是隻有一天。例如,假設有7次作業的學分和完成時間如下:
輸入
第一行一個整數N,表示作業的數量;
接下來N行,每行包括兩個整數,第一個整數表示作業的完成期限,第二個數表示該作業的學分。
輸出
輸出一個整數表示可以獲得的最大學分。保證答案不超過C/C++的int範圍。
樣例輸入
複製樣例資料
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
樣例輸出
15
提示
對於20%的資料,N≤103;
對於40%的資料,N≤104;
對於60%的資料,N≤105;
對於100%的資料,N≤106,作業的完成期限均小於7×105
思路分析:按照貪心策略來,一定會把學分高的放在前面,然後進行遍歷,能寫的科目就寫,最後得到的答案一定是最優解.但此題的問題是如何確定目前科目前是否還有空天並把它找出來,樓主之前是想用一個標記陣列以及while(i–)挨個遍歷,沒錯,TLE了…然後接觸了並查集這個玩意----另用一個指向陣列並將一個數指向它前一個數,然後用函式呼叫,如果這個數是空就用它,否則就往前推直到找到下一個空的數,再將標記指向它,下次在用它是就不用一個個找了.
附程式碼:
#include<iostream> #include<algorithm> using namespace std; typedef struct homework { int timelimit, score; }Homework; int numb[(int)(1e6 + 5)]; //標記陣列 int before[(int)(1e6 + 5)]; //指向陣列(指向前面第一個空天) Homework hw[(int)(1e6 + 5)]; int cmp(Homework a, Homework b) { if (a.score == b.score) return a.timelimit < b.timelimit; else return a.score > b.score; } int unon(int n) { if (!numb[n]) //定義0為空天,如果這天是空的就直接返回這天 return n; else { before[n] = unon(before[n]); //否則就往前走直到找到空天 return unon(before[n]); } } int main() { int n; while (~scanf("%d", &n)) { for (int i = 1; i <= n; i++) { scanf("%d%d", &hw[i].timelimit, &hw[i].score); before[i] = i-1; } sort(hw+1, hw+1 + n, cmp); //將每門學科按照學分排序 memset(numb, 0, n * sizeof(int)); int sum = 0; for (int i = 1; i <= n; i++) { int yet = unon(hw[i].timelimit); if (yet) { numb[yet] = 1; sum += hw[i].score; if (yet != hw[i].timelimit) //實現指向最前面的空天 before[hw[i].timelimit] = before[yet]; } } printf("%d\n", sum); } return 0; }