hdu5501 The Highest Mark 贪心+动态规划

题目链接: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;
}


你可能感兴趣的:(dp,贪心)