Controlling distance of shuffling

后端 未结 7 1920
醉梦人生
醉梦人生 2020-12-05 05:26

I have tried to ask this question before, but have never been able to word it correctly. I hope I have it right this time:

I have a list of unique elements. I want t

相关标签:
7条回答
  • 2020-12-05 06:07

    Here are two sketches in Python; one swap-based, the other non-swap-based. In the first, the idea is to keep track of where the indexes have moved and test if the next swap would be valid. An additional variable is added for the number of swaps to make.

    from random import randint
    
    def swap(a,b,L):
      L[a], L[b] = L[b], L[a]
    
    def magicFunction(L,d,numSwaps):
      n = len(L)
      new = list(range(0,n))
      for i in xrange(0,numSwaps):
        x = randint(0,n-1)
        y = randint(max(0,x - d),min(n - 1,x + d))
        while abs(new[x] - y) > d or abs(new[y] - x) > d:
          y = randint(max(0,x - d),min(n - 1,x + d))
        swap(x,y,new)
        swap(x,y,L)
      return L
    
    print(magicFunction([1,2,3,4],2,3)) # [2, 1, 4, 3]
    print(magicFunction([1,2,3,4,5,6,7,8,9],2,4)) # [2, 3, 1, 5, 4, 6, 8, 7, 9]
    

    Using print(collections.Counter(tuple(magicFunction([0, 1, 2], 1, 1)) for i in xrange(1000))) we find that the identity permutation comes up heavy with this code (the reason why is left as an exercise for the reader).


    Alternatively, we can think about it as looking for a permutation matrix with interval restrictions, where abs(i - j) <= d where M(i,j) would equal 1. We can construct a one-off random path by picking a random j for each row from those still available. x's in the following example represent matrix cells that would invalidate the solution (northwest to southeast diagonal would represent the identity permutation), restrictions represent how many is are still available for each j. (Adapted from my previous version to choose both the next i and the next j randomly, inspired by user2357112's answer):

    n = 5, d = 2
    
    Start:
    
    0 0 0 x x
    0 0 0 0 x
    0 0 0 0 0
    x 0 0 0 0
    x x 0 0 0
    
    restrictions = [3,4,5,4,3]  # how many i's are still available for each j
    
    1.
    
    0 0 1 x x  # random choice
    0 0 0 0 x
    0 0 0 0 0
    x 0 0 0 0
    x x 0 0 0
    
    restrictions = [2,3,0,4,3] # update restrictions in the neighborhood of (i ± d)
    
    2.
    
    0 0 1 x x 
    0 0 0 0 x  
    0 0 0 0 0
    x 0 0 0 0
    x x 0 1 0  # random choice
    
    restrictions = [2,3,0,0,2] # update restrictions in the neighborhood of (i ± d)
    

    3.
    
    0 0 1 x x
    0 0 0 0 x
    0 1 0 0 0  # random choice
    x 0 0 0 0
    x x 0 1 0
    
    restrictions = [1,0,0,0,2] # update restrictions in the neighborhood of (i ± d)
    
    only one choice for j = 0 so it must be chosen
    
    4.
    
    0 0 1 x x  
    1 0 0 0 x  # dictated choice
    0 1 0 0 0
    x 0 0 0 0
    x x 0 1 0
    
    restrictions = [0,0,0,0,2] # update restrictions in the neighborhood of (i ± d)
    
    Solution:
    
    0 0 1 x x
    1 0 0 0 x
    0 1 0 0 0
    x 0 0 0 1  # dictated choice
    x x 0 1 0
    
    [2,0,1,4,3]
    

    Python code (adapted from my previous version to choose both the next i and the next j randomly, inspired by user2357112's answer):

    from random import randint,choice
    import collections
    
    def magicFunction(L,d):
      n = len(L)
      restrictions = [None] * n
      restrict = -1
      solution = [None] * n
      for i in xrange(0,n):
        restrictions[i] = abs(max(0,i - d) - min(n - 1,i + d)) + 1
      while True:
        availableIs = filter(lambda x: solution[x] == None,[i for i in xrange(n)]) if restrict == -1 else filter(lambda x: solution[x] == None,[j for j in xrange(max(0,restrict - d),min(n,restrict + d + 1))])
        if not availableIs:
          L = [L[i] for i in solution]
          return L
        i = choice(availableIs)
        availableJs = filter(lambda x: restrictions[x] <> 0,[j for j in xrange(max(0,i - d),min(n,i + d + 1))])
        nextJ = restrict if restrict != -1 else choice(availableJs)
        restrict = -1
        solution[i] = nextJ
        restrictions[ nextJ ] = 0
        for j in xrange(max(0,i - d),min(n,i + d + 1)):
          if j == nextJ or restrictions[j] == 0:
            continue
          restrictions[j] = restrictions[j] - 1
          if restrictions[j] == 1:
            restrict = j
    
    print(collections.Counter(tuple(magicFunction([0, 1, 2], 1)) for i in xrange(1000)))
    

    Using print(collections.Counter(tuple(magicFunction([0, 1, 2], 1)) for i in xrange(1000))) we find that the identity permutation comes up light with this code (why is left as an exercise for the reader).

    0 讨论(0)
提交回复
热议问题