1. 题目背景与问题分析
作为一名算法竞赛选手,我最近在刷题时遇到了P2392这道有趣的动态规划题目。题目描述了一位名叫kkksc03的大学生临近期末考试,需要在有限时间内高效复习四门课程的故事。这个场景实在太真实了——相信每个大学生都经历过这种"考前突击"的紧张时刻。
题目给出了四门课程的习题集,每科分别有s1到s4道题目,每道题需要不同的时间完成。我们的目标是帮助kkksc03合理分配他的复习时间,使得完成所有题目所需的总时间最短。这实际上是一个典型的分组背包问题,需要我们将题目合理分配到两个"大脑半球"(可以理解为上午和下午的复习时段)来完成。
2. 算法思路解析
2.1 问题建模
首先我们需要将这个问题转化为标准的算法问题。对于每一科(共四科),我们需要将该科的所有题目分成两组,使得两组完成时间的较大值尽可能小。然后把这四科的最优解相加,就是最终答案。
用数学语言表达就是:
对于每科i(i=1,2,3,4),找到子集S⊆题目集合,使得max(∑S, ∑(题目集合-S))最小。然后将四科的这个最小值相加。
2.2 动态规划解法
这个问题可以使用动态规划来解决。对于每一科,我们可以建立一个DP数组,其中dp[j]表示是否可以用该科的部分题目凑出总时间为j。
具体步骤:
- 计算该科所有题目的总时间sum
- 初始化dp数组,大小为sum/2+1,dp[0]=true
- 对于每个题目,从后往前更新dp数组
- 找到最大的j使得dp[j]=true,则该科的最小时间为max(j, sum-j)
2.3 算法优化
考虑到题目给出的数据范围(每科最多20题,每题最多50分钟),总时间最多1000分钟,所以我们的DP数组大小设为1001就足够了。这个规模在现代计算机上运行效率很高。
3. 代码实现与详解
下面给出完整的C++实现代码,并逐段解释:
cpp复制#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int s[5], a[5][25];
int dp[1205];
int solve(int idx) {
int sum = 0;
for (int i
解锁全文
加入我们的会员,获取最新、最热、最精彩的开发者技术内容