1008 I love exam
比赛WA到爆炸,犯了个蠢错误
这个题不同于分组背包的是,每组物品只能选一个,而且必须选一个. 那么我们可以令
f
(
i
,
j
,
k
)
f(i,j,k)
f(i,j,k) 表示第
i
i
i 门课,花了
k
k
k 天,挂了
p
p
p 科。01背包有个
f
[
i
,
j
]
=
f
[
i
−
1
,
j
]
f[i,j] = f[i - 1, j]
f[i,j]=f[i−1,j] 转移,表示不选第
i
i
i 个物品,但是在这里由于必须要选一组物品,因此不需要从第
i
−
1
i - 1
i−1 层向第
i
i
i 层模拟不选第
i
i
i 组物品的过程,直接做决策即可。因此这个最好也别用滚动数组.
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 55, S = 105, Time = 510, INF = 0x3f3f3f3f;
int g[N][S], f[N][Time][5];
int n, idx, m, t, p;
typedef pair<int, int> P;
unordered_map<string, int> mp;
vector<P> scores[N];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
mp.clear();
idx = 0;
memset(g, 0x3f, sizeof g);
memset(f, -0x3f, sizeof f);
scanf("%d", &n);
for(int i = 1; i <= n; i++) scores[i].clear();
for(int i = 1; i <= n; i++)
{
string s;
cin >> s;
mp[s] = ++idx;
}
scanf("%d", &m);
for(int i = 1; i <= m; i++)
{
string s;
int score, day;
cin >> s;
scanf("%d%d", &score, &day);
scores[mp[s]].push_back({score, day});
}
scanf("%d%d", &t, &p);
for(int id = 1; id <= n; id++)
{
g[id][0] = 0;
for(int i = 1, sz = scores[id].size(); i <= sz; i++)
{
int score = scores[id][i - 1].x, day = scores[id][i - 1].y;
for(int j = 100; j >= score; j--)
{
g[id][j] = min(g[id][j], g[id][j - score] + day);
}
}
}
f[0][0][0] = 0;
for(int i = 1; i <= n; i++)
{
for(int j = t; j >= 0; j--)
{
for(int k = 0; k <= 100; k++)
{
int day = g[i][k];
for(int pp = p; pp >= 0; pp--)
{
int kk = k < 60 ;
if(pp - kk < 0 || j - day < 0) continue;
f[i][j][pp] = max(f[i][j][pp], f[i - 1][j - day][pp - kk] + k);
}
}
}
}
int ans = -INF;
for(int i = 0; i <= t; i++)
for(int pp = 0; pp <= p; pp++)
{
ans = max(ans, f[n][t][pp]);
}
if(ans <= -INF / 2) ans = -1;
printf("%d\n", ans);
}
}