wikioi p1052 地鼠遊戲
題目大意 給出N個任務以及每個任務的獎勵W和完成期限T,要求輸出獲得的最大獎勵。
考察演算法 貪心 並查集 二叉堆
演算法一
這道題目我們很容易想到一個貪心策略:每次讓獎勵最多的任務儘量準時完成。這樣我們可以先把這些任務按照獎勵的數目進行排序,把大的排在前面,先進行放置。假如罰款最多的一個任務的完成期限是T,我們應該把它安排在哪個時段完成呢?應該放在第T個時段,因為放在1~T任意一個位置,效果都是一樣的。一旦出現一個不可能在規定時限前完成的任務,則把其扔到最大的一個空時間段,甚至可以將這個任務要放棄,這樣必然是最優的。
時間複雜度:O((( (NT))) ) 空間複雜度:O((( (N))) ) 期望得分:30分
演算法二
這道題也可以用另外一個貪心策略來解決:對於當前時刻所能完成的任務,選獎勵最大的任務完成。我們可以先把這些任務按照完成期限T進行排序,時間從最大完成期限開始列舉。對於當前時刻,所能完成的任務就是那些完成期限T大於等於當前時刻的任務。於是,每次只要將完成期限與當前時刻相同的任務加入集合中,(接下來列舉時,這些任務也是滿足要求的),再在所能完成的任務中,找出獎勵最大的任務完成,直到時間為零。
時間複雜度:O((( (NT))) ) 空間複雜度:O((( (N))) ) 期望得分:30分
演算法三
在演算法一的基礎上,我們可以發現演算法一的瓶頸之處就在於不能快速找出將這個任務放在哪一個時間來完成,這時候我們可以藉助並查集來優化。
設f[i] 表示跟時間i相距最近的沒被用過的時間的編號(初始化 f[i]=i ),對於當前任務P,我們查找出T[P]的根結點F,如果時間F沒有被佔用,那麼就合併T[P]和F-1,並在時間F完成任務P。具體實現可以參見程式。
時間複雜度:O((( (NlogT))) ) 空間複雜度:O((( (N))) ) 期望得分:100分
演算法四
在演算法二中,我們要做的就是找出當前所能完成任務中獎勵最大的任務。這樣很容易想到用二叉堆來優化。每次列舉時刻,我們只需將新的能完成的任務拼命加入堆中,再維護一下小根堆(注:?應該是大根堆吧,以加分為比較關鍵詞)的性質就可以了。
時間複雜度:O((( (NlogN))) ) 空間複雜度:O((( (N))) ) 期望得分:100分
#include<stdio.h> #include<iostream> #include<algorithm> using namespace std; const int MAX_N = 101; const int MAX_T = 10001; struct node { int time; int score; }A[MAX_N]; bool f[MAX_T]; int N; int ans=0; bool cmp(struct node a,struct node b) { if (a.score>b.score) return true; return false; } int init() { int i; scanf("%d",&N); for (i=1;i<=N;i++) scanf("%d",&A[i].time); for (i=1;i<=N;i++) scanf("%d",&A[i].score); } int work() { sort(A+1,A+1+N,cmp); int i,j; bool p; for (i=1;i<=N;i++) { p=false; for (j=A[i].time;j>=1;j--) { if (!f[j]&&!p) { f[j]=true; p=true; } } if (p) ans+=A[i].score; } } int put() { printf("%d",ans); } int main() { init(); work(); put(); }