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