这题我的状态是 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∼∑ti,这表示的是他最多活的时间,我觉得这是正确的,事实上也过了:
#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 时的最大存活时间
但是我看很多题解都是只枚举到 D 的,我觉得这样不对,因为有些时候会因为状态下表为负而被排除掉,但这些状态实际上可以取到,比如 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 就可以