【洛谷 P2392】kkksc03考前临时抱佛脚 题解(动态规划+01背包)-CSDN博客

114 阅读3分钟

kkksc03考前临时抱佛脚

题目背景

kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。

题目描述

这次期末考试,kkksc03 需要考 4 4 4 科。因此要开始刷习题集,每科都有一个习题集,分别有 s 1 , s 2 , s 3 , s 4 s_1,s_2,s_3,s_4 s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等( A 1 , A 2 , … , A s 1 A_1,A_2,\ldots,A_{s_1} A1​,A2​,…,As1​​, B 1 , B 2 , … , B s 2 B_1,B_2,\ldots,B_{s_2} B1​,B2​,…,Bs2​​, C 1 , C 2 , … , C s 3 C_1,C_2,\ldots,C_{s_3} C1​,C2​,…,Cs3​​, D 1 , D 2 , … , D s 4 D_1,D_2,\ldots,D_{s_4} D1​,D2​,…,Ds4​​)。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 2 2 2 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 5 5 5 行数据:第 1 1 1 行,为四个正整数 s 1 , s 2 , s 3 , s 4 s_1,s_2,s_3,s_4 s1​,s2​,s3​,s4​。

第 2 2 2 行,为 A 1 , A 2 , … , A s 1 A_1,A_2,\ldots,A_{s_1} A1​,A2​,…,As1​​ 共 s 1 s_1 s1​ 个数,表示第一科习题集每道题目所消耗的时间。

第 3 3 3 行,为 B 1 , B 2 , … , B s 2 B_1,B_2,\ldots,B_{s_2} B1​,B2​,…,Bs2​​ 共 s 2 s_2 s2​ 个数。

第 4 4 4 行,为 C 1 , C 2 , … , C s 3 C_1,C_2,\ldots,C_{s_3} C1​,C2​,…,Cs3​​ 共 s 3 s_3 s3​ 个数。

第 5 5 5 行,为 D 1 , D 2 , … , D s 4 D_1,D_2,\ldots,D_{s_4} D1​,D2​,…,Ds4​​ 共 s 4 s_4 s4​ 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

样例 #1

样例输入 #1

1 2 1 3		
5
4 3
6
2 4 3

样例输出 #1

20

提示

1 ≤ s 1 , s 2 , s 3 , s 4 ≤ 20 1\leq s_1,s_2,s_3,s_4\leq 20 1≤s1​,s2​,s3​,s4​≤20。

1 ≤ A 1 , A 2 , … , A s 1 , B 1 , B 2 , … , B s 2 , C 1 , C 2 , … , C s 3 , D 1 , D 2 , … , D s 4 ≤ 60 1\leq A_1,A_2,\ldots,A_{s_1},B_1,B_2,\ldots,B_{s_2},C_1,C_2,\ldots,C_{s_3},D_1,D_2,\ldots,D_{s_4}\leq60 1≤A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​≤60。


思路

在每个科目的循环中,计算每个科目的学习总时间 sum,并遍历每个学习时间,使用当前学习时间更新 dp 数组。

状态转移方程:

dp[k] = max(dp[k], dp[k - hw[j]] + hw[j]);

当每个科目左脑时间与右脑时间尽量接近时,总时间最小。

最后,累加每科所有作业总时间减去 dp[sum/2] 的值,得到完成所有科目的最短总时间。


AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define AUTHOR "HEX9CF"
using namespace std;

const int N = 1e4 + 5;

int ans;
int s[5], hw[N];

int main()
{
    for (int i = 0; i < 4; i++)
    {
        cin >> s[i];
    }
    for (int i = 0; i < 4; i++)
    {
        int sum = 0;
        int dp[N];
        for (int j = 0; j < s[i]; j++)
        {
            cin >> hw[j];
            sum += hw[j];
        }
        memset(dp, 0, sizeof(dp));
        for (int j = 0; j < s[i]; j++)
        {
            for (int k = sum / 2; k >= hw[j]; k--)
            {
                dp[k] = max(dp[k], dp[k - hw[j]] + hw[j]);
            }
        }
        ans += sum - dp[sum / 2];
    }
    cout << ans << endl;
    return 0;
}