#include using namespace std; const int N = 110; // 能量石个数上限 const int M = 10010; // 能量上限 // 用来描述每个能量石的结构体 struct Node { int s; // 吃掉这块能量石需要花费的时间为s秒 int e; // 可以获利e个能量 int l; // 不吃的话,每秒失去l个能量 } q[N]; // 能量石的数组 // 结构体对比函数 bool cmp(const Node &a, const Node &b) { return a.s * b.l < b.s * a.l; } int n; // 能量石的数量 int f[M]; // f[i]:花i个时间得到的最大能量 int idx; // 输出是第几轮的测试数据 int main() { // T组测试数据 int T; scanf("%d", &T); while (T--) { // 初始化为负无穷,预求最大,先设最小 memset(f, -0x3f, sizeof f); scanf("%d", &n); // 总时长,背包容量 int m = 0; int res = 0; // 读入数据 for (int i = 1; i <= n; i++) { scanf("%d %d %d", &q[i].s, &q[i].e, &q[i].l); m += q[i].s; } // 贪心排序 sort(q + 1, q + 1 + n, cmp); // 01背包,注意恰好装满时的状态转移方程的写法 // 不能是至多j,而是恰好j // 这是因为如果时间越长,不见得获取的能量越多,因为能量石会损耗掉 // 恰好的,最终需要在所有可能的位置去遍历一次找出最大值 // 每次清空状态数组 memset(f, 0, sizeof f); for (int i = 1; i <= n; i++) { int e = q[i].e, s = q[i].s, l = q[i].l; for (int j = m; j >= s; j--) { int w = e - (j - s) * l; f[j] = max(f[j], f[j - s] + w); res = max(res, f[j]); } } printf("Case #%d: %d\n", ++idx, res); } return 0; }