Efficient way of generating latin squares (or randomly permute numbers in matrix uniquely on both axes - using NumPy)

前端 未结 5 1640
悲&欢浪女
悲&欢浪女 2021-01-05 00:31

For example, if there are 5 numbers 1, 2, 3, 4, 5

I want a random result like

[[ 2, 3, 1, 4, 5]
 [ 5, 1, 2, 3, 4]
 [ 3, 2, 4, 5, 1]
 [ 1, 4, 5, 2, 3]         


        
5条回答
  •  旧巷少年郎
    2021-01-05 01:18

    EDIT: Below is an implementation of the second solution in norok2's answer.

    EDIT: we can shuffle the generated square again to make it real random. So the solve functions can be modified to:

    def solve(numbers):
        shuffle(numbers)
        shift = randint(1, len(numbers)-1)
        res = []
    
        for r in xrange(len(numbers)):
            res.append(list(numbers))
            numbers = list(numbers[shift:] + numbers[0:shift])
    
        rows = range(len(numbers))
        shuffle(rows)
    
        shuffled_res = []
        for i in xrange(len(rows)):
            shuffled_res.append(res[rows[i]])
    
        return shuffled_res
    

    EDIT: I previously misunderstand the question. So, here's a 'quick' method which generates a 'to-some-extent' random solutions. The basic idea is,

        a, b, c
        b, c, a
        c, a, b
    

    We can just move a row of data by a fixed step to form the next row. Which will qualify our restriction.

    So, here's the code:

    from random import shuffle, randint
    
    
    def solve(numbers):
        shuffle(numbers)
        shift = randint(1, len(numbers)-1)
        res = []
    
        for r in xrange(len(numbers)):
            res.append(list(numbers))
            numbers = list(numbers[shift:] + numbers[0:shift])
    
        return res
    
    
    def check(arr):
        for c in xrange(len(arr)):
            col = [arr[r][c] for r in xrange(len(arr))]
            if len(set(col)) != len(col):
                return False
        return True
    
    
    if __name__ == '__main__':
        from pprint import pprint
        res = solve(range(5))
        pprint(res)
        print check(res)
    

    This is a possible solution by itertools, if you don't insist on using numpy which I'm not familiar with:

    import itertools
    from random import randint
    list(itertools.permutations(range(1, 6)))[randint(0, len(range(1, 6))]
    
    # itertools returns a iterator of all possible permutations of the given list.
    

提交回复
热议问题