hdu(5501)——The Highest Mark
題意:
問題描述 2045年的SD省隊選拔,賽制和三十年前已是完全不同。一場比賽的比賽時間有 tt 分鐘,有 nn 道題目。 第 ii 道題目的初始分值為 A_i(A_i \leq 10^{6})A?i??(A?i??≤10?6??) 分,之后每過一分鐘這道題目的分值會減少 B_iB?i?? 分,并且保證到比賽結束時分值不會減少為負值。比如,一個人在第 xx 分鐘結束時做出了第 ii 道題目,那么他/她可以得到 A_i - B_i * xA?i???B?i???x 分。 若一名選手在第 xx 分鐘結束時做完了一道題目,則他/她可以在第 x+1x+1 分鐘開始時立即開始做另一道題目。 參加省隊選拔的選手 dxy 具有絕佳的實力,他可以準確預測自己做每道題目所要花費的時間,做第 ii 道需要花費 C_i(C_i \leq t)C?i??(C?i??≤t) 分鐘。由于 dxy 非常神,他會做所有的題目。但是由于比賽時間有限,他可能無法做完所有的題目。他希望安排一個做題的順序,在比賽結束之前得到盡量多的分數。 輸入描述 第一行為一個正整數 T(T \leq 10)T(T≤10),表示數據組數(n>200n>200的數據不超過55組)。 對于每組數據,第一行為兩個正整數 n (n \leq 1000)n(n≤1000) 和 t (t \leq 3000)t(t≤3000), 分別表示題目數量和比賽時間。接下來有 nn 行,每行 33 個正整數依次表示 A_i, B_i, C_iA?i??,B?i??,C?i??,即此題的初始分值、每分鐘減少的分值、dxy做這道題需要花費的時間。 輸出描述 對于每組數據輸出一行一個整數,代表dxy這場比賽最多能得多少分 輸入樣例 1 4 10 110 5 9 30 2 1 80 4 8 50 3 2 輸出樣例 88 Hint dxy先做第二題,再做第一題,第一題得分為110-5*(1+9)=60110?5?(1+9)=60,第二題得分為30-2*1=2830?2?1=28,總得分為8888,其他任何方案的得分都小于8888思路:
因為要使得分盡可能的多,所以很容易讓人想到要用貪心法。
這里有一個很巧妙的思路。
首先,我們已經假設已經選出來了我們要選擇哪些題目,那么我們就要確定我們應該以哪種順序做這些題目。
假設我們以x1,x2,,,,,xn的順序做這些題目,那么我們要討論這樣做題目是不是最優的。討論xi,xi+1,考慮交換這兩項的順序,方案是否會變得更優,交換方案中的相鄰兩項,只會對這兩道題的得分有影響,對其余的題目不會產生影響。。
第一種是xi在前面,那么此時我們損耗的分數是A=c[i]*b[i+1];第二種是xi+1在前面,此時我們損耗的分數是B=c[i+1]*b[i];
第一種是當A<=B時,那么我們是不用進行交換的。
第二種是當A>B時,那么我們此時應該交換這兩項。移項得?B_{x_{i+1}} / C_{x_{i+1}} > B_{x_{i}} / C_{x_{i}}B?x?i+1????/C?x?i+1????>B?x?i????/C?x?i????
因此我們先對所有的題目按照這個比值進行排序,接下來,只要按照排好的順序,選擇做哪些題目就可以了。這相當于一個簡單的“背包問題”,使用動態規劃來解決。{dp}_idp?i??表示恰好用了ii分鐘的最高得分。狀態轉移方程為{dp}_i = \max_{1\leq j\leq n}{dp}_{i-C_j} + A_j - (i * B_j)dp?i??=max?1≤j≤n??dp?i?C?j????+A?j???(i?B?j??)。
最主要是想到按照那個比值排序,接下來的就是01背包了。
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<cmath> using namespace std; #define maxn 1010 int dp[3030]; struct node{int a,b,c;double d; }t[maxn]; bool cmp(node a,node b){return a.d>b.d; } int main(){int T;scanf("%d",&T);while(T--){memset(dp,0,sizeof(dp));int n,time=0;scanf("%d%d",&n,&time);for(int i=0;i<n;i++) scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c),t[i].d=(t[i].b*1.0)/t[i].c;sort(t,t+n,cmp);for(int i=0;i<n;i++){for(int j=time;j>=0;j--){if(j>=t[i].c) dp[j]=max(dp[j],dp[j-t[i].c]+t[i].a-j*t[i].b);}}int lmax=-1;for(int i=0;i<=time;i++){lmax=max(lmax,dp[i]);}printf("%d\n",lmax);} }
總結
以上是生活随笔為你收集整理的hdu(5501)——The Highest Mark的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 甲骨文的转型路,道阻且长
- 下一篇: VR+全景播放器+头控讲解-05