A. Acing the contest 状压DP + 思维
题目大意:
(T) 个人参加比赛,你可以任意调换这个 (T) 个人参加比赛的顺序,每个人有生命值。
(P) 个比赛,每个比赛有难度值 (b) 和奖励值 (c)。一个人可以选择参加这个比赛,减少 (b) 的生命值(要保证生命值最后非负),获得 (c) 的奖励。或者跳过这个比赛,或者将这个比赛甩手给下一个人。
求最后得到的奖励值和最大值。
题解:
- (dp[s][i]) 表示的是现在的状态是 (s) ,现在已经解决到问题 (i) 了的最优解
- 转移方程是: (dp[nxt][j] = max(dp[nxt][i],dp[cur][j]+解决到 i 到 j 问题的最优解))
- (val[i][j][k]) 表示解决问题 (i) 到 (j) ,花费生命值为 (k) 的最优解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1<<11][110],val[110][110][110];
/*
* dp[s][i] 表示现在写题了的人的状态是 s,i 表示现在以及写到了第 i 个题目
* val[i][j][k] 表示从 i 到 j 个问题,花费 k 个生命值的最优解
*/
int e[11],d[110],s[110];
int main() {
int t, p;
scanf("%d%d", &t, &p);
for (int i = 1; i <= t; i++) scanf("%d", &e[i]);
for (int i = 1; i <= p; i++) scanf("%d", &d[i]);
for (int i = 1; i <= p; i++) scanf("%d", &s[i]);
for (int i = 1; i <= p; i++) {
for (int j = i; j <= p; j++) {
for (int k = 1; k <= 100; k++) {
val[i][j][k] = max(val[i][j][k], val[i][j - 1][k]);
if (k >= d[j]) val[i][j][k] = max(val[i][j][k], val[i][j - 1][k - d[j]] + s[j]);
// if(k<=3)printf("val[%d][%d][%d]=%lld
",i,j,k,val[i][j][k]);
}
}
}
memset(dp, 0xef, sizeof(dp));
dp[0][0] = 0;
ll ans = 0;
int sum = 1 << t;
for (int cur = 0; cur < sum; cur++) {
for (int i = 1; i <= t; i++) {
int tmp = 1 << (i - 1);
if (tmp & cur) continue;
for (int j = 1; j <= p; j++) {
if (dp[cur][j - 1] < 0) continue;
for (int k = j; k <= p; k++) {
dp[cur | tmp][k] = max(dp[cur | tmp][k], dp[cur][j - 1] + val[j][k][e[i]]);
ans = max(ans, dp[cur | tmp][k]);
}
}
}
}
printf("%lld
", ans);
return 0;
}
/*
5 14
3 3 3 3 3
1 1 1 3 1 2 3 4 1 1 1 3 10 2
10 9 8 30 21 22 50 100 10 10 10 32 100 2
*/