【动态规划】将一个包含m个整数的数组分成n个数组,每个数组的和尽量接近,及其变形(Python实现)

本文探讨如何使用动态规划将包含整数的数组平均或按比例分成多个子数组,确保每个子数组的和尽可能接近。文章介绍了平均分配和按比例分配两种方法的思路和Python实现,最终达到人员或工作量分配的均衡。
摘要由CSDN通过智能技术生成

背景

实际的问题来源于LQA系统的人员分配工作量,有两种方式,一种是 平均分配,一种是按给定比例分配。不需要AC,能得到符合题意的解就算达成目标。

平均分配

一个order订单包含一个xls表格,内含若干词条,需要把词条分配给若干LQA,每个人负责的词条总字数大致相近就好,不必完全一致。
词条不可拆分,分配工作量的占比是按字数占比。
另外延伸一个应用情况:
已知现在有x个小组,(小组之间人数差距比较大,假设有的100人,有的10个人,),需要分成n个部门。要求,小组不能拆分,各个部门的人数较为均衡。求,每个部门的小组。

抽象

将一个包含m个整数的数组分成n个数组,每个数组的和尽量接近

input:
# 给定小组及其对应人数
groups = {'a':100, 'b':10, 'c':23, 'd':23, 'e':12, 'f':34, 'g':67, 'h':135, 'i':5, 'j':39, 'k':60, 'l':204}
# 目标部门数
n = 5
output:

groups: [[204], [135], [100, 23], [67, 39, 12, 5], [60, 34, 23, 10]]

思路

这里参照了这个同学的思路
https://cloud.tencent.com/developer/article/1659134
感谢

根据以上思路,核心思想是每一趟遍历一次 数组,每一趟得出一个分组列表,因为需要分为5组,所以进行5趟分组,每一趟从后开始遍历。
遍历的目的是 依次比较每个数value,和剩下的 数的平均值 avg(sum_leftover/(n-i), i 为趟数),
如果 value >=avg,则加入groups,成为一个list,并直接结束循环(因为已经比avg大的话,加上任何数只会偏离avg,增加方差)
如果 value < avg, 则加入groups,成为该趟 list 的第一个成员,继续往后循环,看看是否能加上一个数,使这个分组更接近avg。循环结束后终止这次遍历。

最后一趟,则把剩下所有数字放入最后一个groups 的同一个list。

原文举例:

数组为:500, 18, 28, 2, 27, 35, 22, 10, 6, 5, 3, 2, 1;分为4组

排序为:500, 35, 28, 27, 22, 18, 10, 6, 5, 3, 2, 2, 1

计算平均值 avg = 164.75

遍历数组:

第一轮:500 > avg,取出500单独作为一组;剩余数组为 35, 28, 27, 22, 18, 10, 6, 5, 3, 2, 2, 1
计算avg = 53
第二轮:35 < avg,取出35放入到第二组;
delta=53-35=18;
接下来为28 > 18,继续遍历,27 > 18,22 > 18,18 == 18,于是取出18加入到第二组,结束第二轮,剩余数组为 28, 27, 22, 10, 6, 5, 3, 2, 2, 1
第三轮:28 < avg, 取出28放入到第三组;
delta=53-28=25
27 > delta > 22,27-delta=2,delta-22=3,distance = 2,将22加入临时数组,delta = 3;
18 >3, ... ,5 > 3, 3==3,distance = delta-3 = 0;于是将22和3加入到第三组,结束第三轮,属于数组为 27, 10, 6, 5, 2, 2, 1
第四轮:直接返回剩下数加入到一个组作为第四组
结果:

arr 0 is : 500, sum =  500

arr 1 is : 35 18, sum =  53

arr 2 is : 28 22 3, sum =  53

arr 3 is : 27 10 6 5 2 2 1, sum =  53

实现

大致理解之后我就直接动手做了,没有参照原文的go代码,具体细节的问题没有特别考虑,比如经典 的动态规划一般怎么做,比如这里是否可以不考虑循环中不能remove成员的问题(长度动态变化 的迭代对象不能再次被访问)。
(我在下面的第一次实现中 未在循环中remove,严格遵守了他的语法,而实际上,因为这个for循环里,只会在满足 if 条件的时候才会做remove操作(长度变化),并且remove马上break跳出循环了,不会再进行下一次循环,所以不会报错,符合语法规范,可以大胆remove,可以减少很多不必要的变量,这点我在 按比例分配 时做了)

import numpy as np

def split(groups, n):
    # 求总数
    
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值