状态第二维的枚举范围
查看原帖
状态第二维的枚举范围
255169
__LePetitPrince__楼主2024/5/17 17:18

这题我的状态是 f[i][j] 为处理第 i 个物品且高度 j 时的最大存活时间,状态转移方程是这个:

if (j - a[i].h >= 0 && f[i - 1][j - a[i].h] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j - a[i].h]);
if (f[i - 1][j] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j] + a[i].f);

我的第二维枚举本来是 0∼∑ti0 \sim \sum t_i,这表示的是他最多活的时间,我觉得这是正确的,事实上也过了:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
using namespace std;
const int S = 105, N = 105, I = 1 << 30;
struct N {
	int t, f, h;
	bool operator< (const N &tmp) const {
		return t < tmp.t;
	} 
} a[S];
int m, n, f[1005][2505], lim, sum;
void read(int &x) {
	int s = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') s = s * 10 + c - 48, c = getchar();
	x = s * f;
} 
int main() {
	memset(f, -0x3f, sizeof(f));
	read(m), read(n);
	for (int i = 1; i <= n; i++)
		read(a[i].t), read(a[i].f), read(a[i].h),
		lim = max(lim, a[i].t), sum += a[i].h;
	sort(a + 1, a + n + 1);
	f[0][0] = 10;
	for (int i = 1; i <= n; i++)
		for (int j = 0; j <= sum; j++) {
			if (j - a[i].h >= 0 && f[i - 1][j - a[i].h] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j - a[i].h]);
			if (f[i - 1][j] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j] + a[i].f);
		} 
	//for (int i = 0; i <= n; i++) {
	//	for (int j = 0; j <= m; j++) {
	//		if (f[i][j] < 0) cout << setw(5) << -1;
	//		else cout << setw(5) << f[i][j];
	//	}
	//	cout << endl;
	//}
	int ans = I, len = 0;
	bool can = false;
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= sum; j++) {
			len = max(len, f[i][j]);
			if (j >= m && f[i][j] >= a[i].t) 
				can = true,
				ans = min(ans, a[i].t); // 存在可以爬出的状态 
		}
	//cout << can << endl;
	if (can) printf("%d", ans);
	else printf("%d", len);
	return 0;
}
// f[i][j]: 处理第 i 个物品且高度 j 时的最大存活时间 

但是我看很多题解都是只枚举到 DD 的,我觉得这样不对,因为有些时候会因为状态下表为负而被排除掉,但这些状态实际上可以取到,比如 hack#1:2 1 1 20 20

如果只枚举到 1,就会发现第一个物品不可取然后 WA 掉,我自己把上界改成 D 就 WA 了hack#1:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
using namespace std;
const int S = 105, N = 105, I = 1 << 30;
struct N {
	int t, f, h;
	bool operator< (const N &tmp) const {
		return t < tmp.t;
	} 
} a[S];
int m, n, f[1005][2505], lim, sum;
void read(int &x) {
	int s = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') s = s * 10 + c - 48, c = getchar();
	x = s * f;
} 
int main() {
	memset(f, -0x3f, sizeof(f));
	read(m), read(n);
	for (int i = 1; i <= n; i++)
		read(a[i].t), read(a[i].f), read(a[i].h),
		lim = max(lim, a[i].t), sum += a[i].h;
	sort(a + 1, a + n + 1);
	f[0][0] = 10;
	for (int i = 1; i <= n; i++)
		for (int j = 0; j <= m; j++) {
			if (j - a[i].h >= 0 && f[i - 1][j - a[i].h] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j - a[i].h]);
			if (f[i - 1][j] >= a[i].t) f[i][j] = max(f[i][j], f[i - 1][j] + a[i].f);
		} 
	//for (int i = 0; i <= n; i++) {
	//	for (int j = 0; j <= m; j++) {
	//		if (f[i][j] < 0) cout << setw(5) << -1;
	//		else cout << setw(5) << f[i][j];
	//	}
	//	cout << endl;
	//}
	for (int i = 0; i <= n; i++)
		if (f[i][m] >= a[i].t) {
			cout << a[i].t;
			return 0;
		}
	int ans = 0;
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= m; j++) ans = max(ans, f[i][j]);
	cout << ans;
	return 0;
}
// f[i][j]: 处理第 i 个物品且高度 j 时的最大存活时间 

求问为啥题解枚举到 D 就可以

2024/5/17 17:18
加载中...