【蓝桥杯 分果果】

这篇博客介绍了蓝桥杯竞赛中关于糖果分配的问题,旨在找到最小化小朋友分到糖果最大重量和最小重量差的方案。博主探讨了题目要求,提出了不能使用二分法而应采用动态规划来解决,并详细解释了动态规划的状态转移方程,最后给出了代码实现。

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

【蓝桥杯 分果果】

题目描述

小蓝要在自己的生日宴会上将 n 包糖果分给 m 个小朋友。每包糖果都要分出去,每个小朋友至少要分一包,也可以分多包。
小蓝已经提前将糖果准备好了,为了在宴会当天能把糖果分得更平均一些,小蓝要先计算好分配方案。
小蓝将糖果从 1 到 n 编号,第 i 包糖果重 wi。小朋友从 1 到 m 编号。每个小朋友只能分到编号连续的糖果。小蓝想了很久没想出合适的分配方案使得每个小朋友分到的糖果差不多重。因此需要你帮他一起想办法。为了更好的分配糖果,他可以再买一些糖果,让某一些编号的糖果有两份。当某个编号的糖果有两份时,一个小朋友最多只能分其中的一份。请找一个方案,使得小朋友分到的糖果的最大重量和最小重量的差最小,请输出这个差。
例如,小蓝现在有 5 包糖果,重量分别为 6, 1, 2, 7, 9,如果小蓝要分给两个小朋友,则他可以将所有糖果再买一份,两个小朋友都分到 1 至 5 包糖果,重量都是 25,差为 0。
再如,小蓝现在有 5 包糖果,重量分别为 6, 1, 2, 7, 9,如果小蓝要分给三个小朋友,则他可以将第 3 包糖果再买一份,第一个小朋友分 1 至 3 包,第二个小朋友分 3 至 4 包,第三个小朋友分第 5 包,每个小朋友分到的重量都是 9,差为 0。
再如,小蓝现在有 5 包糖果,重量分别为 6, 1, 2, 7, 9,如果小蓝要分给四个小朋友,则他可以将第 3 包和第 5 包糖果再买一份,仍然可以每个小朋友分到的重量都是 9,差为 0。
再如,小蓝现在有 5 包糖果,重量分别为 6, 1, 2, 7, 9,如果小蓝要分给五个小朋友,则他可以将第 4 包和第 5 包糖果再买一份,第一个小朋友分第 1 至 2 包重量为 7,第二个小朋友分第 3 至 4 包重量为 9,第三个小朋友分第 4 包重量为 7,第四个和第五个小朋友都分第 5 包重量为 9。差为 2。

解题思路

题目求解的是两个人取得的糖果的差值最小是多少。我的思路是如果我确定了每个人取的糖果的最大值max_v,然后只需要考虑每个人尽量取到的不超过max_v的最大值中最小的那个是多少就好了。
肯定就有人想到可以用二分来解决这个问题了,但是这个题很坑(也可能是我太菜)。通过枚举最大值二分最小的做法会超时4个点。
所以我就想不能二分来求,只能动规来求这个问题。

首先我们设计一个dp状态:dp[i][j][k]表示第i个人取到的糖果的最后一个是j,第i-1个人取到的糖果的最后一个小于等于k。
考虑转移,假设kk为第i-2个人取到的最后一个糖果,那么就有:

dp[i][j][k]=max(dp[i][j][k],min(dp[i-1][k][kk],sum[j]-sum[kk]))
//sum[i]是糖果重量的前缀和

为什么是这样呢?
由于有一些糖果可以购买两次,而且每个人得到的糖果下标连续,我们可以发现第i个人可以得到的糖果一定是以(kk+1,k+1)中的某个下标为开头的,并且以j为结尾的。而且我们肯定是以j为结尾,只要不超过max_v,我们能取多少取多少的。

最后答案为min(max_v-dp[m][n][k])。

上代码

//二分法做的只有60分
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

#define N 105

int n,m,Maxw=1000,Avaw=0;
int w[N];
int dp[N][N][N];
int sum[N];
int erfen(int minx,int maxx){
   
   
	memset(dp,0,sizeof(dp));
	dp[0][0][0]=1;
	for(int i=1;i<=m;i++){
   
   
		for(int j=0;j<=n;j++){
   
   
			for(int k=0;k<=
果果”是一道经典的贪心算法题目,在很多编程竞赛(如蓝桥杯等)中也经常作为考题之一。“那一年”的版本可能是某种变体,下面我们基于一般情况下的“果果”问题给出详细解释与代码实现。 --- ### 题目概述:果果 假设有一堆水果总数为 `n`,现在需要将其尽可能公平地配给 `m` 个人。所谓“公平”,是指每个人获得的水果尽量相等;如果无法完全均,则允许某些人多拿一点或多剩几个果实未被配出去。 #### 示例输入输出 - 输入样例: ``` n = 10, m = 3 ``` - 输出样例: ``` 每人最多可以获得 3 个水果,剩下 1 个未能配。 ``` --- ### 解法思路析 这道题目可以利用简单的数学公式来完成计算,核心思想在于整除运算和取余运算的应用。 1. **确定每人能拿到的最大值** 使用整除 `/` 运算得到平均值,表示每人大概能够获取多少颗水果。 2. **确定剩余的数量** 利用取模 `%` 运算得出总的水果数目不能整除部,这部就是最后剩下的没配完的量。 3. **组合成结果** 最终将上述两步的结果整合进一句话之中呈现即可。 --- Python代码实例如下所示: ```python def distribute_fruits(n, m): if m == 0: return "没有人接收水果!" per_person = n // m # 计算每人应得的数量 remainder = n % m # 剩余的水果数量 result = f"每人最多可以获得 {per_person} 个水果,剩下 {remainder} 个未能配。" return result # 测试案例 total_fruits = 10 people_count = 3 output_message = distribute_fruits(total_fruits, people_count) print(output_message) # 应打印出 "每人最多可以获得 3 个水果,剩下 1 个未能配。" ``` 上面这个例子展示了如何优雅而简洁地解决了该种类型的资源划问题!
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值