如何将m个数尽量平均分成n组

1 背景

在具体的项目中,经常会碰到稍微复杂一点的算法,很多问题都涉及到资源分配,如何将m个自然数尽可能平均分成n组便是其中一个经常会碰到的问题,很多游戏项目中作资源分配时都可能碰到这样的问题。

2 解决方案

针对这个问题,有两种典型的方法,如下分别进行介绍

2.1 暴力法

最简单直接的方法是暴力法,将m个数分成n组,就是对m进行n划分,找出所有的划分,看哪一种最平均。

显然,这是一种最笨的方法,随着m的增长,这些组合的数量会变得极为庞大,如m=10000, n=100时,光把这些组合计算出来都是一件极其费力的事。这种方法显然行不通。

2.2 动态规划算法

为描述方便,以一个具体例子进行分析,假设m个数为:28, 25, 19, 18, 10, 9, 6, 4, 3, 1,如果分成3组,该如何分?分成4组呢?分成5组呢?

在继续分之前,需要明确什么是“尽可能平均”,假设上例中分成三组数据,每组数据之和为sum1, sum2, sum3,m个数的平均值为:mean,则length = [(sum1-mean)2 + (sum2-mean)2 + (sum3-mean)2]1/2,length值最小的分组,分组最平均。

另外一个问题是:是否能找到最优解或者次有解?这个问题有点棘手,但是如果降低要求,能否找到一个并不离奇的解,则很简单。下面介绍一个能找到次优解的方法,在本文中未证明是否是最优解。

  • 首先计算m个数的n平均值,如上例中所有数的和为123,分成3组的平均值mean为41;

  • 将这m个数按从大到小的顺序进行排序,得到(28, 25, 19, 18, 10, 9, 6, 4, 3, 1);

  • 从最大的数max开始选择,如果max >= mean,则直接将max单独分成一组;否则,将max纳入一组g,并为g继续选择是否有新的数可以加入,这是这一算法中最关键的部分:

    (1). 首先计算假设不再有新的数纳入g,则计算delta0 = mean - max和sqrt0 = (mean - max)2
    (2). 然后从剩下的数中寻找最接近delta0的数,此时,按照(1)继续计算delta1和sqrt1,再按照(2)继续,直至不能继续;
    (3). 比较上述过程中可能组合最终的sqrti,选择一个最小的,其核心问题是是否加入一个数到当前组以及加入哪一个数。(这一部分可能描述有些不清楚,请看后面的描述,并在后面的图上动手分组理解

这个问题说起来有些绕,下面以上面具体的例子进行描述:

1 由计算得10个数的总和为123,分成3组的平均值为41;
2 从大到小开始进行分组,首先将28纳入一个组g,因为28 < 41,所以在剩余的数中继续寻找与delta0 =(41 - 28)=13最接近的数;从大到小遍历的过程中,寻找离13最近的数,得到18和10,显然(18-13)2 > (13-10)2,因此将10纳入g;接着,继续再剩余的数中寻找与(13 - 10)等于3最接近的数,最后得到一个分组(28, 10, 3)
同理,按照此方法,可以得到另外的几个组(25,9,6,1),(19,18,4)

在描述例子的过程当中,最核心的问题是寻找与deltai最接近的数时,到底是加入比deltai大的最近的数p还是加入比deltai小的最近的数q

  • 如果(deltai - p)2 > (deltai - q)2,则将q加入分组,继续探索deltai+1 = deltai - q;
  • 如果(deltai - p)2 <= (deltai - q)2,(此时还不能确定到底是加入p还是加入q),则将(deltai - p)2保存,并且继续探索deltai - q;递归地执行上述过程,选择差平方最小的数据加入分组。

显然,上述过程是一个动态规划算法,每个过程都能继续划分为更小的子过程。

在算法执行的过程中,需要频繁地寻找与deltai最接近的数,当采用数组时,其时间复杂度为O(m),当m较小时,还可以接受,当m变大后,则资源浪费严重;如果将原始数据以平衡二叉树的形式存储,其时间复杂度变为O(logm),即使数据规模变大,依然可以接受。

在具体的实现时,在寻找与deltai最接近的数时,如果记住上一时刻的q位置,则不必从头开始遍历二叉树,只需要q的前驱(中序遍历),而非整颗树,因此,划出一个分组,其时间复杂度为O(m*logm),n个分组的时间复杂度为O(m*n*logm)

下面给出上例中涉及的二叉树,感兴趣的童鞋可以手动分析n=4,n=5的划分过程。

10个数分成n组

3 小结

这是一个典型的组合数学问题,通常情况下,类似的问题在第一时间应该想到的是贪心算法或者动态规划算法,想办法理解问题并划分成子问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容