题解:洛谷 P2392 kkksc03考前临时抱佛脚

题目https://www.luogu.com.cn/problem/P2392

解法1:DFS

对于每一科,我们需要将一些题目放入集合 A,其余的放入集合 B

我们设 A 集合中的元素个数为 xB 集合中的元素个数为 y,则答案为(ans):

ans \gets \min(ans,\max(\sum^x_{i=1}A_i,\sum^y_{i=1}B_i))

用 DFS 实现即可。

实现

#include<bits/stdc++.h>
using namespace std;
#define int long long
int s,a[25],S[5],ans,sum=1e18;
void dfs(int x,int A,int B){
	if(x>s){
		sum=min(sum,max(A,B));
		return;
	}
	dfs(x+1,A+a[x],B);
	dfs(x+1,A,B+a[x]);
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>S[1]>>S[2]>>S[3]>>S[4];
	for(int i=1;i<=4;i++){
		s=S[i];
		for(int j=1;j<=s;j++){
			cin>>a[j];
		}
		sum=1e18;
		dfs(1,0,0);
		ans+=sum;
	}
	cout<<ans;
	return 0;
}

解法2:动态规划

可以先回顾一下前面的 DFS 写法。

在 DFS 的写法中,我们是将习题册的题目分成集合 A 和集合 B,使得 \sum^{|A|}_{i=1} A_i\sum^{|B|}_{i=1} B_i 的差最小。

也就是 \sum^{|A|}_{i=1} A_i 要尽可能地接近 \dfrac{m}{2}

那么 \dfrac{m}{2} 就是背包的容量,每道题的做题时间为物品的价格和价值。

对于第 k 本习题册:

dp_{i,j} 表示前 i 个物品选择一些放入剩余容量为 j 的背包中能获得的最大价值。

答案为:\sum^4_{i=1}\max(m-dp_{S_i,m\div 2},dp_{S_i,m\div 2})

其中 S_i 表示第 i 本习题册的题目数量,m 表示习题册题目用时之和。

a_i 表示第 i 道题目需要的时间。

状态转移:

dp_{i,j}= \begin{cases} \max(dp_{i-1,j},dp_{i-1,j-a_i}+a_i)& j\ge a_i \\ \ dp_{i-1,j-1} & \text{otherwise} \end{cases}

记得清空 dp 数组。

实现

/*
对于第 k 科: 

设 dp[i][j] 表示前 i 个物品选择一些放入剩余容量为 j 的背包中能获得的最大价值

答案:max(sum-dp[s[i]][m/2],dp[s[i]][m/2])(m 为习题题目完成时间之和)

状态转移: 

如果第 i 个物品能放入背包中(j>=a[i])则:dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i])

a[i] 表示第 i 道习题需要完成多久

否则:dp[i][j]=dp[i-1][j]

初始化:dp[i][j]=0
*/
#include<bits/stdc++.h>
using namespace std;
int s[5],a[25],dp[25][1205],ans;
void code(int n,int m){
	fill(dp[0],dp[n+1],0);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			dp[i][j]=dp[i-1][j];
			if(j>=a[i]){
				dp[i][j]=max(dp[i][j],dp[i-1][j-a[i]]+a[i]);
			}
		}
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>s[1]>>s[2]>>s[3]>>s[4];
	for(int i=1;i<=4;i++){
		int sum=0;
		for(int j=1;j<=s[i];j++){
			cin>>a[j];
			sum+=a[j];
		}
		code(s[i],sum/2);
		ans+=max(sum-dp[s[i]][sum/2],dp[s[i]][sum/2]);
	}
	cout<<ans;
	return 0;
}

<think>首先,用户的问是关于洛谷P2392题目的贪心策略错误原因分析。用户提到:“我想理解洛谷P2392题目中为何贪心策略(每次选择耗时较少的大脑,将当前最大值放入)是错误的解方法”。所以,我需要解释为什么这个贪心策略在洛谷P2392中是错误的。 回顾引用:用户提供了几个引用,其中引用[3]直接相关:“题目说‘两个大脑可以同时计算2道不同的题目,但是仅限于同一科’、‘必须一科一科的复习’,因此每个科目花费的时间是相互不影响的。也就是其实这里看似有4个科目,其实每个科目依次求出最短复习时间,最后每个科目花费的最短时间相加即为答案。” 这似乎描述了题目的核心:每个科目独立处理,两个大脑可以同时处理同一科目的题目洛谷P2392题目是“kkksc03考前临时抱佛脚”,大意是:有四个科目,每个科目有一些题目,每个题目有耗时。两个大脑可以同时处理两个题目,但仅限于同一科目。目标是找到最小总时间来完成所有题目。 用户描述的贪心策略是:“每次选择耗时较少的大脑,将当前最大值放入”。意思是,在分配题目时,总是将当前最大的题目分配给空闲的大脑或耗时较少的大脑。但用户说这是错误的,我需要解释为什么。 正确的解方法应该是:对于每个科目,独立地求解最小完成时间。因为每个科目必须一科一科地复习,所以每个科目是独立的。对于每个科目,有若干题目,两个大脑可以同时处理两个题目,目标是使完成所有题目的时间最小化。这本质上是将一组数字分成两组,使得两组和的最大值最小化,即最小化最大子集和。 例如,对于一个科目,题目耗时为t1, t2, ..., tn,需要将它们分成两组A和B,使得max(sum(A), sum(B))最小。然后,总时间就是每个科目最小时间的和。 用户提到的贪心策略:总是将当前最大题目分配给当前耗时较少的大脑。这类似于贪心算法在装箱问或任务调度中的应用,但可能不总是最优。 为什么这种贪心策略是错误的?因为它可能不是全局最优。贪心策略在每一步选择局部最优,但在这个问中,局部最优选择可能导致整体不是最优。 例如,考虑一个简科目:题目耗时为[3,3,2,2,2]。如果使用贪心策略(总是将最大题目分配给当前和较小的组): - 初始:A=0, B=0 - 最大是3,分配给A(A较小),A=3 - 下一个最大是3,分配给B(B=0<3),B=3 - 下一个最大是2,分配给A(A=3, B=3,任意),比如A=5 - 下一个2,分配给B(B=3<5),B=5 - 最后一个2,分配给A或B,比如A=7或B=5,max=7 但最优解:A=[3,2,2]=7, B=[3,2]=5,max=7?等等,不对。 更好:A=[3,3]=6, B=[2,2,2]=6,max=6。 在贪心中,我得到了max=7,但最优是6。所以贪心不是最优。 在分配时:如果我将第一个3给A,第二个3给B,然后2给A(A=5),2给B(B=5),2给A(A=7)或B(B=7),max=7。但如果我调整:当有2时,不分配给A或B,但贪心是顺序分配。 贪心策略是排序后,从大到小,每次分配给当前和较小的组。 在[3,3,2,2,2]排序后[3,3,2,2,2] - 分配3给A,A=3 - 分配3给B,B=3(因为B较小) - 分配2给A,A=5(A=3,B=3,A和B相等,但通常分配给第一个或任意,假设分配给A) - 分配2给B,B=5 - 分配2给A,A=7 或给B,B=7,max=7 最优:分配3和3到不同组,然后2,2,2分配:但两个组,所以必须平均分配。最优是A=[3,2,2]=7, B=[3,2]=5? max=7,但sum=10,理想min max是ceil(10/2)=5,但不可能,因为数字大。最小可能max是6,如A=[3,3]=6, B=[2,2,2]=6。 在贪心中,我得到了max=7,但最优是6,所以贪心错误。 在贪心分配时,当分配第三个题目(第一个2)时,A和B都3,分配给A,A=5。然后第四个2给B,B=5。第五个2给A或B,都使一个到7。但如果在分配第三个2时,分配给B,B=5,然后第四个2给A,A=5,第五个2给A或B,同样问。所以贪心总是得到7,但最优是6。 因此,贪心策略不是最优。 在代码实现中,正确的方法是使用动态规划或搜索来求解每个科目的最小完成时间。 现在,用户的问具体是:在洛谷P2392中,为什么“每次选择耗时较少的大脑,将当前最大值放入”是错误的。 所以,我需要解释这个策略为什么失败。 此外,根据系统指令: - 所有行内数学表达式用$...$,例如$max(sum(A), sum(B))$ - 独立公式用$$...$$ - 使用中文回答 - 生成相关问 - 引用段落末尾添加引用标识 - 回答结构清晰 参考引用中,引用[3]直接相关。 我的回答结构: 1. 简要介绍问背景。 2. 解释贪心策略的描述。 3. 分析为什么这个贪心策略错误,通过例子说明。 4. 给出正确的方法。 5. 生成相关问。 使用中文。 最后,生成相关问。</think>### 洛谷P2392题解:贪心策略错误原因分析 洛谷P2392题目kkksc03考前临时抱佛脚”的核心是:有四个科目,每个科目包含若干题目,每个题目有固定的耗时。两个大脑可以同时处理两道题目,但仅限于**同一科目**,且科目必须按顺序独立复习(即完成一个科目后才能开始下一个)。目标是找到最小总时间来完成所有题目。用户提到的贪心策略(每次选择当前耗时较少的大脑,并将剩余题目中耗时最大的分配给该大脑)在本中并非最优解,下面我将逐步分析错误原因,并给出正确解法。 #### 1. **问背景与贪心策略描述** - **题目关键约束**: - 两个大脑可以同时处理两道题目,但必须属于同一科目。 - 每个科目必须独立处理,即完成一个科目的所有题目后,才能开始下一个科目。 - 总耗时是每个科目完成时间的总和,每个科目的完成时间取决于两个大脑中耗时较长的那个(因为大脑并行工作)。 因此,对于每个科目,我们需要将题目分成两组(分别分配给两个大脑),使得两组耗时的最大值 $\max(\text{sum}(A), \text{sum}(B))$ 最小化。然后,总耗时为各科目最小完成时间的和[^3]。 - **用户提到的贪心策略**: - 步骤:将题目按耗时降序排序,每次选择当前累计耗时较少的大脑,并将剩余题目中耗时最大的分配给该大脑。 - 伪代码示例: ```python def greedy_strategy(tasks): tasks.sort(reverse=True) # 降序排序 time_A = 0 time_B = 0 for task in tasks: if time_A <= time_B: # 选择耗时较少的大脑(或相等时优先A) time_A += task # 将当前最大题目分配给A else: time_B += task # 分配给B return max(time_A, time_B) # 该科目的完成时间 ``` 这种策略试图在每一步局部优化(平衡大脑负载),但在某些情况下会导致全局非最优。 #### 2. **贪心策略错误的原因分析** 贪心策略失败的根本原因是:**局部最优选择无法保证全局最优,尤其在题目耗时不均匀时,可能造成大脑负载不均衡,导致完成时间增大**。具体原因如下: - **原因1:贪心忽略全局分配平衡** 贪心策略在每一步只考虑当前大脑耗时的比较,但未考虑剩余题目的分布。当题目耗时差异大时,优先分配大题目到“空闲”大脑可能导致后续小题目无法有效平衡负载。例如,考虑一个科目题目耗时为 $[3, 3, 2, 2, 2]$: - **贪心过程**(排序后为 $[3, 3, 2, 2, 2]$): - 分配第一个3:A=0≤B=0,分配给A → A=3, B=0 - 分配第二个3:B=0≤A=3,分配给B → A=3, B=3 - 分配第一个2:A=3≤B=3,分配给A → A=5, B=3 - 分配第二个2:B=3≤A=5,分配给B → A=5, B=5 - 分配第三个2:A=5≤B=5,分配给A → A=7, B=5 → 完成时间 $\max(7,5)=7$ - **最优解**:A组 $[3,2,2]=7$,B组 $[3,2]=5$?不对!实际最优是A组 $[3,3]=6$,B组 $[2,2,2]=6$,完成时间为6(因为 $\max(6,6)=6$,且总和12,最小可能最大值为6)。 贪心得到7,但最优是6,错误原因在于:当分配第三个题目(第一个2)时,贪心选择“当前耗时较少”的A(A=3, B=3),但分配给A后使A=5,后续无法再平衡。而最优解在早期就将两个3分配到不同组,为小题目预留空间。 - **原因2:题目规模与分布的影响** 贪心策略在题目耗时均匀时可能接近最优,但本题目耗时可能高度偏斜(如大题目多)。例如,科目题目为 $[4,4,3,3,3]$: - 贪心过程:分配顺序 $[4,4,3,3,3]$ → A=4, B=4 → A=7(分配3), B=7(分配3)→ 最后一个3分配给A或B → $\max(10,7)=10$ 或 $\max(7,10)=10$。 - 最优解:A组 $[4,3,3]=10$,B组 $[4,3]=7$?不对!最优是A组 $[4,4]=8$,B组 $[3,3,3]=9$,完成时间9。 贪心得到10,最优为9,错误在于贪心过早分配小题目,未保留大题目平衡的机会。 - **数学分析**: 设一个科目有题目耗时 $t_1, t_2, \dots, t_n$(已排序),贪心策略的目标是使 $\max(S_A, S_B)$ 最小,其中 $S_A$ 和 $S_B$ 是两组和。贪心算法的时间复杂度为 $O(n \log n)$,但无法保证最优,因为它等价于“装箱问”的贪心变种,其近似比可能高达 $\frac{4}{3}$(即最坏比最优解差33%)[^2]。在本中,由于每个科目独立,贪心的累积误差会放大总耗时。 #### 3. **正确解法:独立科目 + 子集和最小化** 正确解法基于题目约束:**每个科目独立处理,总时间 = 各科目最小完成时间之和**[^3]。对于每个科目,问转化为:将题目分成两组,使 $\max(S_A, S_B)$ 最小。这不是贪心可解决的,而需用动态规划(DP)或搜索: - **动态规划方法**: - 定义 $dp[j]$ 表示是否能用一组题目凑出和 $j$(布尔值)。 - 对于每个科目,计算题目总耗时 $sum$,目标是最小化 $\max(S_A, S_B)$,等价于最小化 $S_A$(或 $S_B$)满足 $S_A \geq \lceil sum/2 \rceil$。 - 步骤: 1. 计算该科目总耗时 $sum$。 2. 初始化 $dp[0] = \text{True}$,其他为 False。 3. 遍历每个题目耗时 $t$,更新 $dp$:$dp[j] = dp[j] \lor dp[j - t]$ for $j$ from $sum$ down to $t$。 4. 找到最小 $k \geq \lceil sum/2 \rceil$ 使得 $dp[k] = \text{True}$,则完成时间为 $k$(因为 $\max(k, sum - k) = k$)。 - 时间复杂度:$O(n \times sum)$,但题目耗时小,可行。 - **例子演示**(科目题目 $[3,3,2,2,2]$): - $sum = 12$,$\lceil 12/2 \rceil = 6$。 - DP 过程:能凑出和包括 0,2,3,4,5,6,7,... 最小 $k \geq 6$ 是 6(如 $[3,3]$ 或 $[2,2,2]$),完成时间 = 6。 - 总时间:对每个科目求最小完成时间后求和。 正确解法代码框架(Python): ```python def min_subject_time(tasks): total = sum(tasks) dp = [False] * (total + 1) dp[0] = True for t in tasks: for j in range(total, t - 1, -1): if dp[j - t]: dp[j] = True for k in range((total + 1) // 2, total + 1): # 从ceil(sum/2)开始 if dp[k]: return k # 完成时间 = k # 主函数:处理四个科目 subjects = [list1, list2, list3, list4] # 每个科目题目耗时列表 total_time = 0 for tasks in subjects: total_time += min_subject_time(tasks) print(total_time) ``` #### 4. **总结与启示** 在洛谷P2392中,贪心策略(“选择耗时较少的大脑,放置当前最大值”)错误的原因是它只关注局部平衡,忽略了题目耗时的全局分布,导致负载不均和完成时间偏大。正确方法是利用科目独立的特性,对每个科目使用动态规划求解最小最大子集和。贪心策略虽简,但仅适用于特定分布(如耗时均匀),本需更精确的优化[^3][^4]。 如果您有具体数据或代码实现疑问,我可以进一步分析!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值