hdu5501 The Highest Mark 贪心+动态规划

来源:互联网 发布:大数据广告精准投放 编辑:程序博客网 时间:2024/05/18 04:37

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


0 0
原创粉丝点击