2021杭电第二场

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[i1,j] 转移,表示不选第 i i i 个物品,但是在这里由于必须要选一组物品,因此不需要从第 i − 1 i - 1 i1 层向第 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值