以下のプログラムは、低コストのヒューリスティックです。それが行うことは、あるラウンドでソートされたリストの一方の端から値を選択し、次のラウンドでもう一方の端から値を選択することにより、小さな値と一緒に大きな値を配置する「バケット」間で値を分配することです。ラウンド ロビンで配布を行うことで、バケットあたりの要素数に関する規則が満たされることが保証されます。これはヒューリスティックであり、アルゴリズムではありません。これは、優れたソリューションを生成する傾向があるためですが、より優れたソリューションが存在しないという保証はありません。
理論的には、十分な値があり、それらが均一または正規分布している場合、バケットに値をランダムに配置するだけで、バケットの平均が同じになる可能性があります。データセットが小さいと仮定すると、このヒューリスティックは適切なソリューションの可能性を高めます。データセットのサイズと統計的分布について詳しく知ることは、より優れたヒューリスティックまたはアルゴリズムを考案するのに役立ちます。
from random import randint, seed
from itertools import cycle,chain
def chunks(q, n):
q = list(q)
for i in range(0, len(q), n):
yield q[i:i+n]
def shuffle(q, n):
q = list(q)
m = len(q)//2
left = list(chunks(q[:m],n))
right = list(chunks(reversed(q[m:]),n)) + [[]]
return chain(*(a+b for a,b in zip(left, right)))
def listarray(n):
return [list() for _ in range(n)]
def mean(q):
return sum(q)/len(q)
def report(q):
for x in q:
print mean(x), len(x), x
SIZE = 5
COUNT= 37
#seed(SIZE)
data = [randint(1,1000) for _ in range(COUNT)]
data = sorted(data)
NBUCKETS = (COUNT+SIZE-1) // SIZE
order = shuffle(range(COUNT), NBUCKETS)
posts = cycle(range(NBUCKETS))
buckets = listarray(NBUCKETS)
for o in order:
i = posts.next()
buckets[i].append(data[o])
report(buckets)
print mean(data)
複雑さは、並べ替えステップのために対数です。これらはサンプル結果です:
439 5 [15, 988, 238, 624, 332]
447 5 [58, 961, 269, 616, 335]
467 5 [60, 894, 276, 613, 495]
442 5 [83, 857, 278, 570, 425]
422 5 [95, 821, 287, 560, 347]
442 4 [133, 802, 294, 542]
440 4 [170, 766, 301, 524]
418 4 [184, 652, 326, 512]
440
バケットのサイズに関する要件が支配的であることに注意してください。これは、元のデータの分散が大きい場合、平均が近くにならないことを意味します。このデータセットで試すことができます:
data = sorted(data) + [100000]
含まれているバケット100000
は、少なくとも別の 3 つのデータムを取得します。
私は、子供たちのグループがさまざまな額面の紙幣のパックを手渡され、このゲームのルールに従ってそれらを共有するように言われた場合に何をするかというヒューリスティックな考えを思いつきました. これは統計的に妥当であり、O(log(N)) です。