随机将阵列分成至少3个具有均匀分布的块

时间:2014-12-23 20:30:19

标签: java arrays random groovy

我有一个大小为n的数组,并希望将其分解为m个大小至少为3的块。例如, 给出数组

[1,2,3,4,5,6,7,8,9,10]

和m = 3,我们可以将其分解为

a=[1,2,3,4][5,6,7][8,9,10]
b=[1,2,3][4,5,6,7][8,9,10]
c=[1,2,3][4,5,6][7,8,9,10]

我们可以认为这些解决方案由对(4,3,3)(3,4,3)和(3,3,4)表示。 我想要一个给定数组,n和m的函数,返回一个随机解决方案并返回具有均匀分布的这些解决方案(这样你就不会比任何其他解决方案更有可能得到一个特定的解决方案)。 (此函数需要适用于n = 50,因此出于性能原因,我们无法通过计算所有可能的解决方案来实现此目的。)

因此,在上面的例子中,这种方法将在三分之一的时间内返回[4,3,3],[3,4,3]在三分之一的时间内返回,[3,3,4]为三分之一当时。

4 个答案:

答案 0 :(得分:0)

只是一个想法:

假设m = 3,n = 20。我们能做的就是做到这一点:

  1. 选择介于m和n之间的数字 - 2 * m(3到14之间)
  2. 假设我们随机6.这将是第一组,我们称之为p1
  3. 在[m,[n - m - p1]]的新子集之间选择一个数字,即[3,20 - 6 - 3]或[3,11]
  4. 的子集
  5. 假设我们滚动10.这是p2
  6. 余数(或p3)的大小为20-p1-p2 = 4
  7. 最终设定为[6,10,4]

    这会有用吗?它也不需要对原始列表进行任何迭代。您唯一的迭代将超过m而不依赖于n。

    我可以尝试使变量m更通用(步骤1需要稍微改变,步骤3和5将在循环中)但我相信如果这个解决方案可以接受,你可以解决它给你。 步骤1的重写示例为:

    Choose a number between m and n - [m - 1] * m

答案 1 :(得分:0)

这会有用吗?

def randomCollate(item, chunk) {
    def collated = item.collate( chunk )
    def remainder = collated.reverse().takeWhile { it.size() != chunk }.flatten()
    def randomIdx = new Random().nextInt( ( collated - remainder ).size() )
    collated[randomIdx] += remainder
    collated - [ remainder ]
}

randomCollate( 1..50, 3 )

答案 2 :(得分:0)

我刚才有的另一个想法

  1. 计算大小为m的阵列数量以及大小为m + 1(或不同的sice)的阵列数量。我们将这些值称为x和y。
  2. 计算可能的排列量[3,3,4],[3,4,3],[4,3,3] - > 3个排列(x + y)Py(二项式系数)
  3. 从0中选择随机排列 - 可能的排列。让我们称之为Z。
  4. 从现在开始,我不知道如何做到这一点,但我会尝试这样做:
  5. 想象一下,你得到一个带有n位数的二进制数,其中y是零。获取Zst可能的二进制数,其中只有y个零和x个。
  6. 二进制示例:100101101
  7. 您的结果将是[x,y,y,x,y,x,x,y,x]
  8. 我希望你理解我的意思。

答案 3 :(得分:0)

对于每个步骤,允许随机范围n-m*minmin在您的示例中为3);然后从该范围中选择一个数字,将min添加为r。如果m2,则会返回rn-r的列表。否则返回rn-r, m-1递归调用的结果。洗牌,你有大块的随机大小。

rnd = new Random()

// build the chunk size list to randomly split `n` elements in `m` parts, 
// where each part is at least of size `min`
// needs a shuffle afterwards
def s(n,m,min=3) {
    def l = n-m*min // the range where we can pick a random offset
    def r = min + (l?rnd.nextInt(l):0) // result for this step with optional random part
    m==2 ? [r,n-r] : [r]+s(n-r,m-1) // only two remaining? pick result and remainder, or recurse
}

def tests = [[9,3,3],[10,3,3],[27,9,3],[4,2,2]]
1000.times{
    tests.each{ n,m,min ->
        def r = s(n,m,min) 
        assert r.sum()==n
        assert r.size()==m
        assert r.every{ it>= min }
    }
}

def items = (0..9).collect() // test list
def slices = s(items.size(),3) // get the chunk sizes
Collections.shuffle(slices) // shuffle the result
// create ranges and use them to get the slices; should be another one or two methods
println slices.inject([sum:0,result:[]]) { r,s -> r.result<<items[((r.sum)..(r.sum+s-1))]; r.sum+=s; r }.result
//=> e.g. [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]