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;
}
posted @ 2023-11-03 12:25  加固文明幻景  阅读(11)  评论(0编辑  收藏  举报