hdu6968:I love exam

题目链接

题意:有 n n n场考试,直接去考都只能得0分,现在给你一些复习资料,他们对应上述考试的一种,需要 c o s t cost cost天来阅读,阅读完之后对应的考试可以多考 v a l val val分,问有 t t t天来复习,如果挂科数不大于 p p p,最多能拿多少分

解法:进行两次dp操作
①记为 d p 1 [ i ] [ j ] dp1[i][j] dp1[i][j]; d p 1 [ i ] [ j ] dp1[i][j] dp1[i][j]表示第 i i i场考试获得 j j j分的最小花费时间,即求一个空间为 m a x u p maxup maxup,物品价值为天数,体积为可以增加的分数的01背包,由于考试分数上限为100,所以当两本资料提升分数之和大于100时只能算一百分,我们这里把 m a x u p maxup maxup设为大于两百,因为读两本资料最多就能提升200分,读两本就已经达到上限了,自然不会在读完这两本资料后花时间去读通常考试的资料。

for (int i = 1; i <= m; i++) {
            int id = rmap[book[i].name];//对应的考试序号
            for (int j = maxup; j >= book[i].val; j--) {
                dp1[id][j] = min(dp1[id][j], dp1[id][j - book[i].val] + book[i].cost);
            }
        }

②记为 d p 2 [ i ] [ j ] [ k ] dp2[i][j][k] dp2[i][j][k],表示考完第i场一共花了j的时间来复习,且挂了k科
此时有两种情况需要讨论:
        一是 k = = 0 k==0 k==0,即 d p 2 [ i ] [ j ] [ k dp2[i][j][k dp2[i][j][k]只能由 d p 2 [ i − 1 ] [ j − d p 1 [ i ] [ f ] ] [ g ] + m i n ( f , 100 ) dp2[i-1][j-dp1[i][f]][g]+min(f,100) dp2[i1][jdp1[i][f]][g]+min(f,100)转移而来, f f f代表第i场的分数;
        二是 k ! = 0 k!=0 k!=0,此时根据f的大小有第i场及不及格两种情况,则 d p 2 [ i ] [ j ] [ k ] dp2[i][j][k] dp2[i][j][k] d p 2 [ i − 1 ] [ j − d p 1 [ i ] [ f ] ] [ k − ( f < 60 ) ] + m i n ( f , 100 ) dp2[i-1][j-dp1[i][f]][k-(f<60)]+min(f,100) dp2[i1][jdp1[i][f]][k(f<60)]+min(f,100)
        此时可以看出上面将 m a x u p maxup maxup设为200的原因:将两本资料视为一本提升分数为100,花费天数为两者花费之和的资料

AcCode:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<thread>
#include<set>

//#define int long long
#define inf 0x3f3f3f3f

using namespace std;

inline int max(int a, int b) { return (a > b) ? a : b; }
inline int min(int a, int b) { return (a < b) ? a : b; }
inline int number(char c) { return c - '0'; }

const int N = 1e5 + 100;
const int M = 210;

struct node {
    int cost, val;
    string name;
}book[N];

int dp1[55][M];//第i场考试获得j分的最小天数
int dp2[55][510][5];//第i场考试复习j天包括这场一共挂了k次的最高分
string exams[55];
int maxup = 200;


signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t; cin >> t;
    while (t--) {
        int n; cin >> n;
        map<string, int> rmap;
        for (int i = 1; i <= n; i++) {
            cin >> exams[i];
            rmap[exams[i]] = i;
            dp1[i][0] = 0;
        }
        int m; cin >> m;
        for (int i = 1; i <= m; i++) {
            cin >> book[i].name >> book[i].val >> book[i].cost;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = maxup; j; j--) dp1[i][j] = inf;
            dp1[i][0] = 0;
        }
        for (int i = 1; i <= m; i++) {
            int id = rmap[book[i].name];
            for (int j = maxup; j >= book[i].val; j--) {
                dp1[id][j] = min(dp1[id][j], dp1[id][j - book[i].val] + book[i].cost);
            }
        }
        int maxd, maxp; cin >> maxd >> maxp;
        for (int i = 1; i <= n; i++) {//第几场
            for (int g = 0; g <= maxp && g <= i; g++) {//挂科数
                if (g == 0) {
                    for (int f = maxup; f >= 60; f--) {//分数
                        for (int j = maxd; j >= dp1[i][f]; j--) {//花费的时间
                            dp2[i][j][g] = max(dp2[i][j][g], dp2[i - 1][j - dp1[i][f]][g] + min(f, 100));
                        }
                    }
                }
                else {
                    for (int f = maxup; f >= 0; f--) {//分数
                        for (int j = maxd; j >= dp1[i][f]; j--) {//花费的时间
                            dp2[i][j][g] = max(dp2[i][j][g], dp2[i - 1][j - dp1[i][f]][g - (f < 60)] + min(f, 100));
                        }
                    }
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= maxd; i++) {
            for (int j = 0; j <= maxp; j++) {
                ans = max(ans, dp2[n][i][j]);
            }
        }
        if (ans >= (n - maxp) * 60)cout << ans << endl;
        else cout << -1 << endl;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= maxd; j++) {
                for (int k = 0; k <= maxp; k++) {
                    dp2[i][j][k] = 0;
                }
            }
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值