题目链接:https://www.luogu.org/problemnew/show/P1926
题目背景
数学是火,点亮物理的灯;物理是灯,照亮化学的路;化学是路,通向生物的坑;生物是坑,埋葬学理的人。 文言是火,点亮历史宫灯;历史是灯,照亮社会之路;社会是路,通向哲学大坑;哲学是坑,埋葬文科生。——小A
题目描述
小A“刷题”十分猖狂,明目张胆地“刷题”。他现在在小书童里发现了n样他喜欢的“题目”,每“题”都有他的需要时间,而老师布置了m项作业,每项作业都有它的需要时间及分值,老师规定k分以上算及格。小A只剩r个单位时间,他
想在及格的基础上更多地“刷题”。
输入输出格式
输入格式:
第一行:n m k r。第二行:n个数,代表每“题”他的需要时间。第三行:m个数。表示每项作业它的需要时间。第四行:m个数。代表每项作业它的分值。
输出格式:
一个数,代表小A能刷几道题
输入输出样例
输入样例#1:
3 4 20 100
15 20 50
10 15 40 40
5 5 10 15
输出样例#1:
2
说明
没有不能及格的情况
对于100%的数据,n≤10,m≤10,k≤50,r≤150
解题思路:
其实题目的意思就是,从这一批作业中挑选一些作业,使得这些作业的总分数大于或等于k,并且完成这些作业的总时间尽可能的短(从而留下更多的时间刷题)。本题的难点就在于,如何如何实现上述问题。
其实这题是01背包的变种问题,对每一项作业都有两种选择,选或者不选。不难发现,我们可以将问题看成一个倒过来的01背包问题,即将题目要求转变为,从这一批作业中挑选一些作业,使得这些作业的总
分数小于或等于sumscore-k,并且使这些作业的总时间尽可能的长(即写作业的时间尽可能的短),使题目转换为一个简单的01背包问题。
#include <bits/stdc++.h> using namespace std; int main() { int n, m, k, r; while (cin >> n >> m >> k >> r) { int i, j; int que[15],time[15],score[15]; int sumscore = 0; int sumtime = 0; for (i = 0; i < n; i++)cin >> que[i]; for (i = 0; i < m; i++){ cin >> time[i]; sumtime += time[i]; } for (i = 0; i < m; i++){ cin >> score[i]; sumscore += score[i]; } int res = sumscore - k; int dp[200]; memset(dp, 0, sizeof(dp)); //一定记得要将dp数组初始化,否则输出的是0 for (i = 0; i < m; i++) { for (j = res; j >= score[i]; j--) { dp[j] = max(dp[j], dp[j - score[i]] + time[i]); } } int lefttime = r - (sumtime - dp[res]); //剩余用来刷题的时间。(可能会有人以为剩余刷题时间就是dp[res]) sort(que, que + n); int ans = 0; i = 0; while (lefttime>=que[i]) { ans++; i++; lefttime -= que[i]; } cout << ans << endl; } return 0; }
2018-05-15