【蓝桥杯 分果果】

【蓝桥杯 分果果】

题目描述

小蓝要在自己的生日宴会上将 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++){
   
  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值