HDU - I love exam

题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=6968

Problem Description
Student Z doesn’t love exams

The exam was about to be done soon, but student Z didn’t even read the book, He had collapsed.

Student Z has a total of n exams, and there are still t days before the start of the exam, which means he still has t days to PREVIEW.

But student Z couldn’t even read the textbooks, and couldn’t review it at all. Fortunately, a kind classmate gave him m sets of review materials. The i set of materials can improve the grades of the si course. The i set of materials needs to be studied for yi days. You can increase xi points later (the upper limit of each course is 100 points, so after it is upgraded to 100 points, there will be no further increase).and note that each set of review materials can only be used once.

Student Z now has a zero-point level in every course. it is impossible to review all the materials, so he needs to choose some materials to review, but he can fail at most p courses in this semester (if the score of one course is less than 60 points will fail), otherwise he will be talked to by the professor.

Student Z now wants to know the maximum points he can get in all courses under the premise of fail no more than p courses this semester. If he cannot meet the conditions, please output −1 .

Input
A positive integer T ( T ≤ 10 ) T (T≤10) T(T10) in the first line represents the number of test cases.

For each test case:

The first line contains a positive integer n ( n ≤ 50 ) n (n≤50) n(n50) represents the total number of courses in this semester.

The second line contains n strings which length is no more than 15, representing the course name of each course in this semester.

The third line contains a positive integer m ( m ≤ 15000 ) m (m≤15000) m(m15000) represents the number of review materials he obtained.

In the next m lines, each line have a string s and two positive integers x ( 1 ≤ x ≤ 10 ) x(1≤x≤10) x(1x10) and y ( 1 ≤ y ≤ 10 ) y(1≤y≤10) y(1y10) , representing the course of this set of materials review, the improved scores and The number of days required for learning(data assurance this course was studied this semester ).

The last line has two integers t , p ( 1 ≤ t ≤ 500 , 0 ≤ p ≤ 3 ) t, p(1≤t≤500,0≤p≤3) t,p(1t500,0p3)represents the number of review days that student Z has and the upper limit of the number of failed courses in this semester.

Output
For each test case, output a line with a positive integer representing the maximum score that student Z can obtain in the case of meeting the conditions .If he must be talked to by the professor, output −1。

Sample Input
1
3
mathematics physics signals
20
physics 10 1
physics 10 1
physics 10 1
physics 10 1
physics 10 1
physics 10 1
physics 10 1
mathematics 10 1
mathematics 10 1
mathematics 10 1
mathematics 10 1
mathematics 10 1
mathematics 10 1
mathematics 10 1
signals 10 1
signals 10 1
signals 10 1
signals 10 1
signals 10 1
signals 10 2
19 1

Sample Output
190

题目大意:
即将到来一场考试,共有n个科目。你有m份复习资料,每份复习资料 m i m_i mi可以帮助你给某个科目提升某个科目 a i a_i ai分,但是你需要花 b i b_i bi天的时间去复习。每个科目的分数上限是100分,啥都不复习你只能考0分。现给定限制:你至多只能有t天的复习时间,至多只能有p个科目的分数低于60,求在符合限制的情况下,你最多能考出多少的总分?如果都达不到要求,请输出-1.

思路:
先对复习资料进行分类,用背包求解出每个科目要达到i分,至少需要复习多少天,可设为f[x][i],以下假定x为科目编号。然后再转化出每个科目给定i天复习时间能达到的最高分数,可设为M[x][i]。
然后利用dp[i][j]表示给定i天复习时间,挂j个科目的情况下能达到的最大总分。
首先,每个M[x][i]是一个值,它有小于60与否的区分。
那么状态转移方程就是
dp[j][k] = max(dp[j - l][k - 1] + M[i][l], dp[j][k]); (M[x][i]<60)
dp[j][k] = max(dp[j - l][k] + M[i][l], dp[j][k]); (M[x][i]>=60)

(其实一开始的思路和这个有不小的差异,打算只用每个科目要达到i分至少需要的天数,然后将至多挂p科的限制视作至少要及格n -p科,但是Debug很久了还是不知道问题出在哪)

AC代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<string>
#define endl '\n'
using namespace std;
map<string, int> number;
int f[55][125];
int M[55][505];
int dp[505][55];
struct material {
    int pee;
    int val;
};
vector<material> materials[55];
int main(void) {
    //freopen("0.in", "r", stdin);
    int T;
    cin >> T;
    while (T--) {
        number.clear();
        memset(f, 0x3f, sizeof f);
        memset(M, 0, sizeof M);
        memset(dp, -0x3f, sizeof dp);
        for (int i = 1; i <= 50; i++)
            materials[i].clear();
        string name;
        int n, m;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> name;
            number[name] = i;
        }
        cin >> m;
        for (int i = 1; i <= m; i++) {
            cin >> name;
            int val, pee;
            cin >> val >> pee;
            materials[number[name]].push_back({ pee, val });
        }
        int t, p;
        cin >> t >> p;
        for (int i = 1; i <= n; i++) {
            f[i][0] = 0;
            int e = materials[i].size();
            for (int j = 0; j < e; j++) {
                for (int k = 120; k >= materials[i][j].val; k--) {
                    f[i][k] = min(f[i][k], f[i][k - materials[i][j].val] + materials[i][j].pee);
                }
            }
            for (int j = 120; j >= 0; j--) {
                f[i][j] = min(f[i][j], f[i][j + 1]);
            }
            for (int j = 0; j <= 100; j++) {
                if (f[i][j] <= 500)
                    M[i][f[i][j]] = max(M[i][f[i][j]], j);
            }
        }
        dp[0][0] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = t; j >= 1; --j) {
                for (int k = p; k > 0; --k)dp[j][k] = dp[j][k - 1];
                dp[j][0] = -1e9;
                for (int k = 0; k <= p; ++k)
                    for (int l = 1; l <= f[i][100] && l <= j; ++l) {
                        if (M[i][l] >= 60)dp[j][k] = max(dp[j - l][k] + M[i][l], dp[j][k]);
                        else if (k)dp[j][k] = max(dp[j - l][k - 1] + M[i][l], dp[j][k]);
                    }
            }
            dp[0][0] = -1e9;
        }
        int ans = -1;
        for (int i = 1; i <= t; ++i) {
            for (int j = 0; j <= p; ++j) {
                ans = max(ans, dp[i][j]);
            }
        }
        
        cout << ans << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值