HDU 5501 The Highest Mark

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5501

The Highest Mark

 
 Accepts: 32
 
 Submissions: 193
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
2045年的SD省队选拔,赛制和三十年前已是完全不同。一场比赛的比赛时间有 tt 分钟,有 nn 道题目。
第 ii 道题目的初始分值为 A_i(A_i \leq 10^{6})Ai(Ai106) 分,之后每过一分钟这道题目的分值会减少 B_iBi 分,并且保证到比赛结束时分值不会减少为负值。比如,一个人在第 xx 分钟结束时做出了第 ii 道题目,那么他/她可以得到 A_i - B_i * xAiBix 分。
若一名选手在第 xx 分钟结束时做完了一道题目,则他/她可以在第 x+1x+1 分钟开始时立即开始做另一道题目。
参加省队选拔的选手 dxy 具有绝佳的实力,他可以准确预测自己做每道题目所要花费的时间,做第 ii 道需要花费 C_i(C_i \leq t)Ci(Cit) 分钟。由于 dxy 非常神,他会做所有的题目。但是由于比赛时间有限,他可能无法做完所有的题目。他希望安排一个做题的顺序,在比赛结束之前得到尽量多的分数。
输入描述
第一行为一个正整数 T(T \leq 10)T(T10),表示数据组数(n>200n>200的数据不超过55组)。
对于每组数据,第一行为两个正整数 n (n \leq 1000)n(n1000)t (t \leq 3000)t(t3000), 分别表示题目数量和比赛时间。接下来有 nn 行,每行 33 个正整数依次表示 A_i, B_i, C_iAi,Bi,Ci,即此题的初始分值、每分钟减少的分值、dxy做这道题需要花费的时间。
输出描述
对于每组数据输出一行一个整数,代表dxy这场比赛最多能得多少分
输入样例
1
4 10
110 5 9
30 2 1
80 4 8
50 3 2
输出样例
88
Hint
dxy先做第二题,再做第一题,第一题得分为110-5*(1+9)=601105(1+9)=60,第二题得分为30-2*1=283021=28,总得分为8888,其他任何方案的得分都小于8888

 

题解:

  贪心+01背包。

贪心:

  假设比赛时间无限大,每一道题目都能做完,那么你按照bi/ci由大到小排序的顺序完成所有题目会得到优成绩,

  为什么呢?

    任意两个相邻的题目i和j(i<j),先做i,你会损失分数:ci*bj;先做j,你会损失cj*bi,如果我们要先完成i,则有ci*bj<=cj*bi,即bi/ci>=bj/cj。

  现在考虑有限时间内,如果最优解中的几个问题不是按照这个顺序来完成的,那么我们经过以上操作调整之后能使损失减小,从而得到更优解。

  所以这个贪心是正确的。

dp:

  贪心完之后,跑一遍01背包就可以了。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 1010;
 7 const int maxt = 3030;
 8 
 9 struct Node {
10     int a, b, c;
11     bool operator < (const Node& tmp) {
12         return b*tmp.c>c*tmp.b;
13     }
14 }node[maxn];
15 
16 int N, T;
17 int dp[maxn][maxt];
18 
19 int main() {
20     int tc;
21     scanf("%d", &tc);
22     while (tc--) {
23         scanf("%d%d", &N, &T);
24         for (int i = 1; i <= N; i++) {
25             scanf("%d%d%d", &node[i].a, &node[i].b, &node[i].c);
26         }
27         sort(node + 1, node + N + 1);
28         /*
29         for(int i = 1; i <= N; i++) printf("%d ", node[i].a);
30         printf("\n");
31         */
32         memset(dp[0], 0, sizeof(dp[0]));
33         for (int i = 1; i <= N; i++) {
34             for (int j = 0; j < node[i].c; j++) dp[i][j] = dp[i - 1][j];
35             for (int j = node[i].c; j <= T; j++) {
36                 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - node[i].c]+node[i].a-node[i].b*j);
37             }
38         }
39         int ans = 0;
40         for (int i = 0; i <= T; i++) ans = max(ans, dp[N][i]);
41         printf("%d\n", ans);
42     }
43     return 0;
44 }
View Code

 优化:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 const int maxn = 1010;
 8 const int maxt = 3030;
 9 
10 struct Node {
11     int a, b, c;
12     bool operator < (const Node& tmp) {
13         return b*tmp.c>c*tmp.b;
14     }
15 }node[maxn];
16 
17 int N, T;
18 int dp[maxt];
19 
20 int main() {
21     int tc;
22     scanf("%d", &tc);
23     while (tc--) {
24         scanf("%d%d", &N, &T);
25         for (int i = 1; i <= N; i++) {
26             scanf("%d%d%d", &node[i].a, &node[i].b, &node[i].c);
27         }
28         sort(node + 1, node + N + 1);
29         memset(dp, 0, sizeof(dp));
30         for (int i = 1; i <= N; i++) {
31             for (int j = T; j >= node[i].c; j--) {
32                 dp[j] = max(dp[j], dp[j - node[i].c] + node[i].a - node[i].b*j);
33             }
34         }
35         int ans = 0;
36         for (int i = 0; i <= T; i++) ans = max(ans, dp[i]);
37         printf("%d\n", ans);
38     }
39     return 0;
40 }
View Code

 

 

你可能感兴趣的:(HDU 5501 The Highest Mark)