[贪心 + dp] 疯狂的火神
问题描述
火神为了训练,决定单挑 n n n 个人。
由于火神训练时间有限,最多只有 t t t 分钟,所以他可以选择一部分人来单挑,由于有丽子的帮助,他得到了每个人特定的价值,每个人的价值由一个三元组 ( a , b , c ) (a, b, c) (a,b,c) 组成,表示如果火神在第 x x x 分钟打倒了这个人,他就会得到 a − b × x a - b \times x a−b×x 的经验值,当前这个人他需要 c c c 分钟来打倒。
现在火神想知道,他最多可以得到多少经验值,由于火神本来就很笨,所以他希望你来帮他计算出他最多可以得到多少经验值。
输入格式
第一行一个正整数 T T T ,表示数据组数。
对于每组数据,第一行为两个正整数 n n n 和 t t t ,表示跟火神单挑的人的个数和火神的训练时间。
下面 n n n 行,每行三个正整数 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci ,表示每个人的价值,含义见题目。
输出格式
对于每组数据输出一行一个整数表示火神最多能得到多少经验值。
样例
样例输入1:
1
4 10
110 5 9
30 2 1
80 4 8
50 3 2
样例输出1:
88
数据范围
对于 20 % 20\% 20% 的数据, 1 ≤ n ≤ 10 1 \le n \le 10 1≤n≤10。
对于 50 % 50\% 50% 的数据, 1 ≤ n ≤ 18 1 \le n \le 18 1≤n≤18。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1000 , 1 ≤ t ≤ 3000 , 1 ≤ C i ≤ t , 1 ≤ A i ≤ 1 0 6 1 \le n \le 1000, 1 \le t \le 3000, 1 \le C_i \le t, 1 \le A_i \le 10^6 1≤n≤1000,1≤t≤3000,1≤Ci≤t,1≤Ai≤106。
对于 n ≤ 200 n \le 200 n≤200 的数据, 1 ≤ T ≤ 10 1 \le T \le 10 1≤T≤10。
对于 n > 200 n > 200 n>200 的数据, 1 ≤ T ≤ 5 1 \le T \le 5 1≤T≤5。
保证每个人贡献的经验值到训练结束都不会变成负数。
题解
首先,我们先确定 m m m 个人单挑,再确定顺序。
先确定 m m m 个人,假设他们分别是 x 1 , x 2 , … x n x_1, x_2, \ldots x_n x1,x2,…xn。
交换 x i x_i xi 和 x i + 1 x_{i + 1} xi+1,交换前损失了 C x i × B x i + 1 + K C_{x_i} \times B_{x_{i + 1}} + K Cxi×Bxi+1+K( K K K 是另外位置的值),交换后损失了 C x i + 1 × B x i + K C_{x_{i + 1}} \times B_{x_i} + K Cxi+1×Bxi+K。
因此,只需考虑 C x i × B x i + 1 + K C_{x_i} \times B_{x_{i + 1}} + K Cxi×Bxi+1+K 和 C x i + 1 × B x i + K C_{x_{i + 1}} \times B_{x_i} + K Cxi+1×Bxi+K 的大小,如果 C x i × B x i + 1 + K > C x i + 1 × B x i + K C_{x_i} \times B_{x_{i + 1}} + K > C_{x_{i + 1}} \times B_{x_i} + K Cxi×Bxi+1+K>Cxi+1×Bxi+K,就要交换。简化一下就是 C x i × B x i + 1 > C x i + 1 × B x i C_{x_i} \times B_{x_{i + 1}} > C_{x_{i + 1}} \times B_{x_i} Cxi×Bxi+1>Cxi+1×Bxi,即 B x i + 1 C x i + 1 > B x i C x i \frac{B_{x_{i + 1}}}{C_{x_{i + 1}}} > \frac{B_{x_i}}{C_{x_i}} Cxi+1Bxi+1>CxiBxi。
排完序后,用动态规划解决。
用 f i f_i fi 表示第 i i i 分钟的最高经验值,状态转移为 f i = m a x ( f i − C j + A j − i × B j ) ( i ≤ j ≤ n ) f_i = max(f_{i - C_j} + A_j - i \times B_j)(i \le j \le n) fi=max(fi−Cj+Aj−i×Bj)(i≤j≤n)。
答案就是 m a x ( f i ) ( 0 ≤ i ≤ t ) max(f_i)(0 \le i \le t) max(fi)(0≤i≤t)。
int T;
int n, m;
struct node{int x, y, z;//x, y, z 对应 a, b, c
}a[1010];
bool cmp(node p, node q){return p.y * q.z > p.z * q.y;
}
int f[3010];//dp
int ans = 0;
int main(){scanf("%d", &T);while(T --){ans = 0;memset(f, 0, sizeof(f));输入sort(a + 1, a + n + 1, cmp);//dpfor(int i = 1; i <= n; ++ i){for(int j = m; j >= a[i].z; -- j){f[j] = max(f[j - a[i].z] + a[i].x - j * a[i].y, f[j]);}}for(int i = 1; i <= m; ++ i){ans = max(ans, f[i]);}printf("%d\n", ans);}
}