P1802 5 倍经验日
P1802 5 倍经验日
基本思路
还是零一板子,只是在枚举小于当前所需药水量时需要考虑输家的加分。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, x;
int F[9000];
int win[1010], lose[1010], v[1010];
int main() {
cin >> n >> x;
for (int i = 1; i <= n; i++) {
cin >> lose[i] >> win[i] >> v[i];
}
for (int i = 1; i <= n; i++) {
for (int j = x; j >= 0; j--) {
if (j >= v[i])
F[j] = max(F[j], F[j - v[i]] + win[i]);
else
F[j] = max(lose[i], F[j]);
}
}
cout << (long long)F[x] * 5;
return 0;
}
但是这犯了两点错误
- 状态转移错误
- 当
j < v[i]
时,我想当然认为F[J] = F[J - J] + lose[I]
自然就推出F[J] = lose[I]
- 然而,
F[J - J] = F[0]
也是有值的,即lose[i]
,即每一层都是上层的值再加上输的值。
- 当
- 忽略贪心策略
- 仅仅如此,并不能求出最优解
- 当输的时候,无论如何一定是什么药都不出而得到输家经验输的最赚,所以无论\(j\)与\(v[i]\)的关系,都一律在输的时候不用掉任何药剂,即转移方程上
F[J]
的\(j\)不减任何东西,直接加lose[i]
.
代码实现
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, x;
int F[9000];
int win[1010], lose[1010], v[1010];
int main() {
cin >> n >> x;
for (int i = 1; i <= n; i++) {
cin >> lose[i] >> win[i] >> v[i];
}
for (int i = 1; i <= n; i++) {
for (int j = x; j >= 0; j--) {
if (j >= v[i])
F[j] = max(F[j] + lose[i], F[j - v[i]] + win[i]);
else
F[j] = max(F[j] + lose[i], F[j]);
}
}
cout << (long long)F[x] * 5;
return 0;
}