题目链接:https://www.acwing.com/problem/content/736/
解题思路:
首先我们假定一个序列:a1, a2, a3, …, an这个序列就是最终的序列,其中最终的序列中可能会有贡献为0的点,所有即使把贡献为0的点抽出去,也不会造成任何影响,并且此时对于ai, aj(i < j)来说,如果将其调换位置则造成的贡献相对于原来的顺序来说一定小于或者等于0。
根据这个性质我们可以得到一个不等式:
假设目前的时间为t,则有:
ei + ej - t * li - (t + si) * lj >= ei + ej - t * lj - (t + sj) * li。
对着个不等式进行化简可以得到如下:
si / li <= sj / lj。(神奇,简化后发现和e没有关系了)
贴上代码一份:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 105, M = 10005;
struct Node {
double cal;
int s, e, l;
}node[maxn];
int T, n, m;
int f[maxn][M];
inline bool cmp(Node a, Node b) {
return a.cal < b.cal;
}
int main(void) {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
int count = 1;
while(T --) {
m = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
int &a = node[i].s;
int &b = node[i].e;
int &c = node[i].l;
double &d = node[i].cal;
scanf("%d%d%d", &a, &b, &c);
if(c == 0) d = 1000000;
else d = a * 1.0 / c;
m += a;
// printf("%d %d %d\n", node[i].s, node[i].e, node[i].l);
}
sort(node + 1, node + 1 + n, cmp);
//for(int i = 1; i <= n; i ++)
// printf("%d %d\n", node[i].e, node[i].s);
memset(f, -1, sizeof f);
for(int j = 0; j <= m; j ++) f[0][j] = 0;
for(int i = 0; i <= n; i ++) f[i][0] = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
//不选
f[i][j] = f[i - 1][j];
//选择
if(j >= node[i].s)
f[i][j] = max(f[i][j], f[i - 1][j - node[i].s] + max(0, node[i].e - (j - node[i].s) * node[i].l));
// printf("%d %d\n", f[0][0], f[i][j]);
}
int fi = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
fi = max(fi, f[i][j]);
printf("Case #%d: %d\n", count ++, fi);
}
return 0;
}
总结:对于DP这样字的题目,时常和贪心结合在一起。自己被坑了的地方:f[0][0]没有进行初始化,在这里花了很多的时间,下次一定要好好的堆自己的代码进行检查,尤其是对于初始化的部分。