题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5501
思路:首先将问题简单化,每道题有ti的时间消耗,给定T时间内要完成若干题目使得分值最大,很容易想到背包问题。但是本题中的value是随着时间减小的,因此背包的顺序也会影响最优值。如果物品数量的规模在16左右,可以使用状态压缩来做:,其中
,dp[i][j]表示j分钟结束时状态为i,k为题目的标号。但是本题中的n范围为1000以内,所以不可能考虑所有的解题顺序,因此考虑用贪心。
假设最优解的解题顺序为,到
时为x分钟,若交换i题和j题的解题顺序得
。由于两种方式只有
和
的解题顺序不一样,所以最后的value值差异只与这两题有关。则有:
化简得:。因此最优的解题顺序为:按照
降序。确定顺序后再按背包问题求解。代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1005
#define M 3005
#define max(a, b) (a) > (b) ? (a) : (b)
struct Node{
int a, b, time;
friend bool operator< (const Node& n1,const Node& n2){
return double(n1.b) / n1.time > double(n2.b) / n2.time;
}
}probs[N];
int f[M];
int main(){
int tc, n, t;
scanf("%d", &tc);
while(tc --){
scanf("%d %d", &n, &t);
for(int i = 0; i < n; ++i)
scanf("%d %d %d", &probs[i].a, &probs[i].b, &probs[i].time);
sort(probs, probs + n);
memset(f, -1, sizeof(f));
f[0] = 0;
int ans = 0;
for(int i = 0; i < n; ++i){
int ti = probs[i].time;
for(int j = t; j >= ti; --j){
if(f[j - ti] == -1)
continue;
f[j] = max(f[j], f[j - ti] + probs[i].a - probs[i].b * j);
}
}
for(int i = 0; i <= t; ++i)
ans = max(ans, f[i]);
printf("%d\n", ans);
}
return 0;
}