原題 傳送門
【題目描述】
老師在開學第一天就把所有作業都布置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為10,要求在6天內交,那么要想拿到這10學分,就必須在第6天結束前交。
每個作業的完成時間都是只有一天。例如,假設有7次作業的學分和完成時間如下:
作業號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
期限 | 1 | 1 | 3 | 3 | 2 | 2 | 6 |
學分 | 6 | 7 | 2 | 1 | 4 | 5 | 1 |
最多可以獲得15學分,其中一個完成作業的次序為2,6,3,1,7,5,4,注意可能d還有其他方法。
你的任務就是找到一個完成作業的順序獲得最大學分。
【輸入】
第一行一個整數N,表示作業的數量。
接下來N行,每行包括兩個整數,第一個整數表示作業的完成期限,第二個數表示該作業的學分。
【輸出】
輸出一個整數表示可以獲得的最大學分。保證答案不超過longint范圍。
【輸入樣例】
7 1 6 1 7 3 2 3 1 2 4 2 5 6 1
【輸出樣例】
15
第一眼看這個題,和智力大沖浪有點像,甚至還比那個題簡單些,不用判斷做不完怎么辦。
貪心策略:
為了使學分盡可能的多,我們要盡可能得做學分多的作業,我們先按照學分從大到小排序,然后枚舉每一個作業,盡量讓這個作業貼着期限完成;
我們可以從某一個作業的期限往前找,若找到沒安排作業的時間點就將它安排上。
代碼如下:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct homework { int k,date; }a[1000001]; int read() { char ch=getchar(); int a=0,x=1; while(ch<'0'||ch>'9') { if(ch=='-') x=-x; ch=getchar(); } while(ch>='0'&&ch<='9') { a=(a<<3)+(a<<1)+(ch-'0'); ch=getchar(); } return a*x; } int cmp(homework x,homework y) { return x.k>y.k; //按照學分從大到小排序 } int n,sum,hash[1000001]; int main() { n=read(); for(int i=1;i<=n;i++) { a[i].date=read(); a[i].k=read(); } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) { int bj=1; for(int j=a[i].date;j>=1;j--) //盡量讓作業貼着期限做,來減少對其他作業的影響 { if(hash[j]==0) { hash[j]=1; bj=0; sum+=a[i].k; break; } } } cout<<sum<<endl; return 0; }
但是將這份代碼交上去后我們發現有兩個點TLE了!我們要進一步優化!
如果我們對某一個作業 i 進行安排,發現從a[i].date枚舉到1它們的hash都為1,也就是說:從1~a[i].date都已經安排滿了,安排不了其他的作業了;
我們可以用q來記錄這個a[i].date,對於后面的作業,如果它的期限a[i+1].date<=q,說明這個作業一定安排不了,我們直接跳出就好了,不用再枚舉了;
AC代碼如下:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct homework { int k,date; }a[1000001]; int read() { char ch=getchar(); int a=0,x=1; while(ch<'0'||ch>'9') { if(ch=='-') x=-x; ch=getchar(); } while(ch>='0'&&ch<='9') { a=(a<<3)+(a<<1)+(ch-'0'); ch=getchar(); } return a*x; } int cmp(homework x,homework y) //按照學分從大到小排序 { return x.k>y.k; } int n,sum,q,hash[1000001]; int pan(int x) { for(int i=a[x].date;i>=1;i--) { if(hash[i]==0) { hash[i]=1; return 1; } } q=a[x].date; //如果到了這里,說明1~a[x].date已經安排滿了,用q記錄下來 return 0; } int main() { n=read(); for(int i=1;i<=n;i++) { a[i].date=read(); a[i].k=read(); } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) { if(a[i].date<q) continue; //直接跳出,節省時間 if(pan(i)) sum+=a[i].k; } printf("%d\n",sum); return 0; }