背景
之前做项目的时候遇到一个需求:假设有不同金额(价值)的物件,需要每天以下面两种方式分配到人,保证以自然月累积平,同时物件在第二天金额可能会发生变化或者物件从人A调整到人B,因此在第二天需要以最新的物件拥有情况分配新的物件数据。
- 优先金额平,其次数量平分配到人
- 优先数量平,其次金额平分配到人
针对上述需求,在基于大量数据金额随机分布的特征情况下,采用贪心思想的思路进行了实现。
前置条件
1.每天的物件具有一定数据量,金额随机分布
2.需要分配的物件列表
T
m
T_m
Tm
3.要分配到的人列表
P
n
P_n
Pn
实现思路
1.优先金额平,其次数量平
(1)对要分配的物件列表
T
m
T_m
Tm进行排序,按金额降序排序;
(2)对要分配到的人列表
P
n
P_n
Pn进行排序,按已分金额升序排序,如果已分金额相等,按已分物件数量升序排序;
(3)取
T
m
T_m
Tm的第一个物件分配给
P
n
P_n
Pn第一个人;
(4)将
P
n
P_n
Pn第一个人与列表后面的人进行交换,直到满足第(2)步的排序要求;
(5)继续按第(3-4)进行分配,直到所有的物件分配完毕。
2.优先数量平,其次金额平
在这种分配方式中,先将物件列表 T m T_m Tm按金额降序进行排序,再将人列表 P n P_n Pn按已分数量升序排序,如果已分数量相同按金额升序排序。
思想
(1)第一次(第一天)分配时,
P
n
P_n
Pn初始已分配金额和数量均为0,采用贪心将
T
m
T_m
Tm剩余未分配物件中金额最大的一个分配给
P
n
P_n
Pn的第一个人(该人已分数量最少,已分数量相同的情况下已分金额最少),每次分配后重排
P
n
P_n
Pn使列表再次有序。
T
m
T_m
Tm分配完成后,
P
n
P_n
Pn每个人已分户数差距小于等于1(逐个分配策略)。
(2)再次(第二天)分配时,
P
n
P_n
Pn的初始状态会出现两种情况:
- 已分数量与上一次的分配结果保持一致,但是物件价值的变化导致已分金额可能会有变化。采用(1)相同的贪心策略进行分配(逐个分配策略)。
- 已分数量与上一次的分配结果不一致,因为已分物件在人员之间的调整。在分配的时候需要优先填平已分数量最少的人,填平数量时的物件考虑不能直接取未分配物件金额最大的,为了保证已分金额的尽可能平均,需要在做填平操作时每次取金额最大和最小的物件进行分配(填平分配策略)。在做填平时,如果拥有最少数量的人数大于等于剩余物件数,直接采用逐个分配策略,完成分配。
伪代码
Begin
while(start<=end):
判断填平标识fillFlag,Pn列表中人已分配物件最大数量-最小数量>1值为true,否则值为false
if(fillFlag为false):
//1.执行逐个分配策略
while(start<=end):
将一个物件分配给Pn第一个人
调整Pn第一个人位置使列表重新有序
start++
else:
//2.执行填平分配策略
计算剩余未分配物件数remainThingCount和有最少物件数量的人数minPersonCount
if(remainThingCount<=minPersonCount):
//2.1逐个分配
while(start<=end):
将一个物件分配给Pn第一个人
调整Pn第一个人位置使列表重新有序
start++
else:
//2.2填平操作
每次分配剩余物件金额最大和最小的两个给Pn第一个人
调整Pn第一个人位置使列表重新有序
start++
end--
End
时间复杂度分析
T
m
T_m
Tm排序:
O
(
m
l
o
g
m
)
O(mlog_m)
O(mlogm)
P
n
P_n
Pn排序:
O
(
n
l
o
g
n
)
O(nlog_n)
O(nlogn)
P
n
P_n
Pn重排:
O
(
n
)
O(n)
O(n)
1.逐个分配策略:
O
(
m
l
o
g
m
)
O(mlog_m)
O(mlogm)+
O
(
n
l
o
g
n
)
O(nlog_n)
O(nlogn)+
O
(
m
n
)
O(mn)
O(mn)=
O
(
m
n
)
O(mn)
O(mn)
2.填平分配策略:
O
(
m
l
o
g
m
)
O(mlog_m)
O(mlogm)+
O
(
n
l
o
g
n
)
O(nlog_n)
O(nlogn)+
O
(
m
n
)
O(mn)
O(mn)=
O
(
m
n
)
O(mn)
O(mn)
时间复杂度:
O
(
m
n
)
O(mn)
O(mn)