得分
描述
现在 zql 手上有 N 道题,他总共有 T 的时间来完成他们中的一些或全部。每道题有一个完成所需时间 t[i] 和一个难度系数c[i]。如果 zql 在剩余 x 个单位时间的时候开始做题 i ,并且能够完成,那么总分加上 x*c[i] 。现在 zql 要从这 N 道题中选出一些在 T 个单位时间内完成,并且按照某种顺序依次完成它们( zql 每个单位时间只能做一道题,并且一旦他决定做某题就会一直做直到做完),那么他最多能够拿到多少分呢?
输入
总共包括 N+1 行
第一行,两个用空格隔开的正整数 N 和 T ,分别表示题目总数和总时间。
第 2 到 N+1 行,每行包含两个正整数,第 i+1 行的两个正整数分别表示 t[i] 和 c[i] 。
输出
总共包括 1 行。一行一个整数,表示最大能够得到的分数。
输入样例 1
3 10 2 1 8 9 2 5
输出样例 1
122
提示
输出解释:最优方案为在剩余 10 个单位时间的时候开始做第 3 题(需要 2 个单位时间),剩余 8 个单位时间的时候开始做第 2 题(需要 8 个单位时间),总得分为 10×5+(10-2)×9=122 。
思路
通过题目显然可以得到一个信息:一个题目,在不同的时间做,会有不同的回报。
那就要先求出在什么时候做什么题效果最好,把得到的回报进行排序,才可以进行背包,也就是类似于贪心的做法。
先假设现在剩余的时间为T,有 a[i] ,和 a[j] 这两道题, t 为需要的时间, c 为题目的难度。
有两种情况:
-
先选 a[i] ; 价值则为
-
先选 a[j] ; 价值则为
只要将两个情况的价值进行比较,就可以求出顺序了。
再进行 01 背包,就好了。
代码
#include<bits/stdc++.h>
using namespace std;
struct Node{
long long t,c;
}a[11111];
long long n,T;
long long dp[11111],ans;
bool cmp(Node a, Node b) {
return T*a.c+(T-a.t)*b.c>T*b.c+(T-b.t)*a.c;
}
int main() {
freopen("score.in","r",stdin);
freopen("score.out","w",stdout);
cin>>n>>T;
for(int i=1;i<=n;i++) {
cin>>a[i].t>>a[i].c;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++) {
for(int j=T;j>=a[i].t;j--) {
dp[j]=max(dp[j],dp[j-a[i].t]+a[i].c*(T-j+a[i].t));
ans=max(dp[j],ans);
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号