洛谷P2393 kkksc03临时抱佛脚

博客详细分析了洛谷P2393题目的解题思路,通过贪心算法和01背包策略解决题目中关于左右脑分配时间的问题。博主指出,要分别求解四个子集的最优解,并强调了在分配时间时让两脑时间接近以达到最优。文章还对比了该问题与小s的游戏机电池贪心题目的不同之处,并提供了一个AC代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【贪心+01背包】洛谷P2393kkksc03临时抱佛脚

NOIOL第三场pj竟然混了240分进了前25%,蒟蒻深感自己DP的薄弱(T3竟然连50分都拿不到),开始在洛谷刷DP,做背包的时候看到的这道题。没想到一道橙题卡了半天

传送门

分析

  题目说了要先做完一个题目集再做后面的,所以只要分别求四个子集的最优解,把它们相加就可以了。
  对于一个子集的最优解,我们就是把总时间分配到左脑和右脑,然后让两者较大的值尽可能小,即让他们尽可能接近
  这里运用了贪心的思想,我们做完一个子集的题目,花费的时间是左脑和右脑花费时间大的那个,比如说左脑3,右脑5,我花费的时间就是5,那么让大的那个尽可能小也就是平均分就是最优解。
  如果你做过一道小s的游戏机电池这道贪心,你会发现到这里好像和那道题思路差不多(要是没看过就忽略掉),但是注意,这道题里开始做一道题目,直到做完,我们才能让这一半大脑去做下一道题,这是和那道电池题目的不同之处,这道题可能我们无法刚好分配出一半的时间给左脑,一半的时间给右脑,因为一道题目不能分割。举个例子,如果3道题分别要花费1、2、5的时间,我无论如何也不能分配出4这个时间吧,但是我可以让一半的大脑在不超过4的情况下,尽可能的大(让1、3在左脑)。这样,左脑和右脑花费时间较多的那个就是所需的最少时间(其实理解了就不难明白,认真看几遍就明白了)。
  经过上面的转换,我们发现求左半边大脑所需的时间就是在总时间不超过sum/2的情况下,选取若干道题目,让时间尽可能的大。这就是道0/1背包的裸题)求出左半边,右半边用sum减去左半边就得出了,最后求左半边和右半边的最大值,就是这个子集所花费的时间。
  最后不要忘了有4个子集,都要算出来啊

  最后蒟蒻贴上AC代码(话说这题是蒟蒻在luogu的第100道AC欸):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s1,s2,s3,s4,minn,sum;
int t[
<think>嗯,用户问的是的P2392题,用C语言解决。首先我需要先了解这道题的具体内容。的题目编号P2392对应的是哪个题目呢?可能用户可能记错了编号,或者我需要确认一下。不过根据常见的题目,P2392应该是一个关于动态规划或者贪心算法的题目,比如可能是背包问题或者某种组合优化的问题。比如,常见的类似题号可能涉及分组背包或者多重背包的问题,或者是某种特定的场景应用。 不过,假设用户没有记错题号,我需要先查找P2392的具体题目描述。由于无法直接访问外部资源,我需要依靠记忆或者逻辑推断。例如,可能题目是“kkksc03考前临时抱佛脚”这道题,常见于类似题号的题目中。这道题的大意是,一个学生需要处理四个科目的练习题,每个科目有多道题目,每道题目需要一定的时间完成。学生可以同时处理两个科目,但同一时间只能处理同一科目的题目,求完成所有科目的最小总时间。这个时候,问题就转化为对每个科目的题目进行分堆,使得两堆的总时间尽可能接近,从而最小化处理该科目的总时间(即较大的那堆的时间)。 如果是这样的话,解题思路应该是:对于每个科目,将该科目的所有题目时间总和计算出来,然后使用动态规划或深度优先搜索来找到将这些题目分成两堆,使得两堆的时间差最小。这样,每个科目的处理时间就是较大的那堆的时间,然后将四个科目的处理时间相加得到答案。 接下来,用户需要用C语言实现这个算法。那么我需要考虑如何将这个问题转化为代码。对于每个科目,首先输入该科目的题目数量,然后读取各个题目的时间,计算总和,然后进行分堆。动态规划的方法可能更高效,特别是当题目数量较多时。 动态规划的思路是,对于每个科目,计算其总时间的一半作为目标,然后找出不超过该目标的最大可能的时间,这样较大的堆就是总时间减去这个值。例如,总时间为sum,那么目标是sum/2,找到最大的不超过sum/2的子集和,这样较大的堆就是sum - dp[sum/2]。 接下来,代码的结构大致如下: 1. 读取四个科目的题目数量s1, s2, s3, s4。 2. 对于每个科目,读取各题目时间,计算总时间sum。 3. 使用动态规划计算该科目的最优分堆时间。 4. 将该科目的最优时间累加到总答案中。 5. 最后输出总答案。 动态规划的部分需要注意数组的大小。例如,对于每个科目,最大的sum可能是每个题目最多30分钟,假设最多有20题,那么sum最大是600,所以dp数组需要至少601的大小。 在C语言中,动态规划的实现需要初始化一个布尔数组dp,其中dp[j]表示是否可以达到时间j。然后对于每个时间t,更新dp数组。最后找到最大的j不超过sum/2且dp[j]为true,然后该科目的处理时间就是sum - j。 需要注意每个科目处理完后,需要重置动态规划的数组。 然后,测试一下边界情况,比如科目只有0题,或者题目时间总和为0的情况,但题目中应该不会有这些情况。 可能的错误点在于数组越界或者动态规划的循环顺序。例如,在更新dp数组时,应该从后往前遍历,避免重复使用同一元素。 综上,代码的大致结构应该是这样的。现在需要将其转化为具体的C语言代码,并确保语法正确。</think> P2392 题目名为“kkksc03考前临时抱佛脚”,属于**动态规划**或**贪心算法**的应用题。下面从问题描述、解题思路和C语言代码实现三个方面逐步解析: --- ### **一、问题描述** - **背景**:学生需要处理四个科目的练习题,每个科目有若干题目,每道题耗时不同。同一时间只能专注一个科目,但可以左右脑并行处理(即同时处理两个题目)。 - **目标**:找到完成所有科目的最小总时间。 - **输入**:四个数字,表示四个科目的题目数量,随后依次给出每个科目的各题耗时。 - **输出**:完成所有科目的最短时间。 --- ### **二、解题思路** #### 1. **问题转化** 每个科目的题目需分成两堆(左脑和右脑处理),使得两堆时间尽可能接近。此时该科目耗时为较大堆的时间。 **数学表达**: 设某科目所有题目耗时总和为 $sum$,找到子集和 $max\_sum \leq sum/2$,则科目耗时为 $sum - max\_sum$。 #### 2. **动态规划解法** 对每个科目,用动态规划计算最大可能的子集和: - **状态定义**:`dp[j]` 表示能否凑出时间 `j`。 - **转移方程**:`dp[j] = dp[j] || dp[j - t]`(`t` 为当前题目时间)。 #### 3. **算法步骤** 1. 输入四个科目的题目数量。 2. 对每个科目: - 计算总时间 `sum`。 - 动态规划求最大子集和 `max_sum`。 - 累加 `sum - max_sum` 到总时间。 3. 输出总时间。 --- ### **三、C语言代码实现** ```c #include <stdio.h> #include <string.h> int solve_subject(int s) { int time[20], sum = 0; for (int i = 0; i < s; i++) { scanf("%d", &time[i]); sum += time[i]; } int dp[601] = {1}; // dp数组初始化为0,dp[0]=1 int target = sum / 2; for (int i = 0; i < s; i++) { for (int j = target; j >= time[i]; j--) { if (dp[j - time[i]]) dp[j] = 1; } } int max_sum = 0; for (int j = target; j >= 0; j--) { if (dp[j]) { max_sum = j; break; } } return sum - max_sum; } int main() { int s1, s2, s3, s4; scanf("%d %d %d %d", &s1, &s2, &s3, &s4); int total = 0; total += solve_subject(s1); total += solve_subject(s2); total += solve_subject(s3); total += solve_subject(s4); printf("%d\n", total); return 0; } ``` --- ### **四、代码解析** 1. **solve_subject函数**:处理单个科目。 - 输入题目耗时并计算总和 `sum`。 - 动态规划求解最大子集和 `max_sum`。 - 返回该科目耗时 `sum - max_sum`。 2. **主函数**: - 读取四个科目的题目数量。 - 分别计算每个科目耗时并累加。 - 输出总时间。 --- ### **五、注意事项** - **时间复杂度**:每个科目动态规划复杂度为 $O(s \cdot sum)$,总体可通过。 - **空间优化**:使用一维数组 `dp` 降低空间复杂度。 - **边界情况**:题目数可能为0(但实际输入保证 $s \geq 1$)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值