如何生成矩阵,其中行的总和是列的总和的排列?

时间:2017-01-21 12:08:05

标签: algorithm math matrix

对于给定的整数N,我想生成一个NxN阶矩阵,其中行的总和是列总和的一些排列。

例如:

3
0 2 3
4 0 1
1 3 0

行总和为5,5,4 总和是5,5,4

两者都是彼此的排列。

如何为任何给定的N生成这样的矩阵?

PS: 我知道对角矩阵,对称矩阵在这里可以工作,像这样的矩阵

3
1 0 0
0 0 1
0 1 0

但我想制作一些随机矩阵。

2 个答案:

答案 0 :(得分:2)

您可以从满足要求但没有排列方面的矩阵开始:因此特定行的总和应等于具有相同索引的列的总和。例如,零矩阵就可以了。

然后随机选择一组列。迭代这些列,并从该列表中选择该行作为 previous 列的索引(因此该行将从列表中最后一列的索引开始)。这会产生一个元素循环,这样如果用相等的常数增加所有元素的值,则保持sum-requirement。此常量可以是1或任何其他整数(尽管0不是非常有用)。

根据需要多次重复此操作,直到您觉得它已经足够混乱为止。例如,您可以决定重复这两次。

最后,您可以对行进行随机播放,以增加随机性:行总和现在与列总和的排列相对应。

这是Python代码:

import random

def increment(a):
    i = 1 # the increment that will be applied. Could also be random
    # choose a random list of distinct columns:
    perm = random.sample(range(len(a)), random.randint(1,len(a)-1))
    row = perm[-1]
    # cycle through them and increment the values to keep the balance
    for col in perm:
        a[row][col] += i
        row = col
    return a

### main ###
n = 7
# create square matrix with only zeroes
a = [[0 for i in range(n)] for j in range(n)]
# repeat the basic mutation that keeps the sum property in tact:
for i in range(n*n): # as many times as you wish
    increment(a)

# shuffle the rows
random.shuffle(a)

一次运行产生了这个矩阵:

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

我在行shuffle之前使用了这个检查来确保sum属性是完整的:

# test that indeed the sums are OK
def test(a):
    for i in range(len(a)):
        if sum(a[i]) != sum([a[j][i] for j in range(len(a))]):
            print('fail at ', i)

答案 1 :(得分:1)

获得相当随机的方法的一种方法如下:

首先创建一个随机对称矩阵。这样的矩阵的行和将等于其列和。

请注意,如果交换任何两行,则其行总和将被置换,但其列总和将保持不变。类似地,如果交换任何两列,则其列的总和被置换,但其行总和保持不变。因此 - 如果你随机交换随机行并多次交换随机列,行和列的总和将是彼此的排列,但原始的对称性将被隐藏。

Python概念证明:

import random

def randSwapRows(matrix):
    i,j = random.sample(list(range(len(matrix))),2)
    matrix[i], matrix[j] = matrix[j], matrix[i]

def randSwapColumns(matrix):
    i,j = random.sample(list(range(len(matrix))),2)
    for row in matrix:
        row[i],row[j] = row[j],row[i]

def randSpecialMatrix(n):
    matrix  = [[0]*n for i in range(n)]
    for i in range(n):
        for j in range(i,n):
            matrix[i][j] = random.randint(0,n-1)
            matrix[j][i] = matrix[i][j]
    #now swap a lot of random rows and columns:
    for i in range(n**2):
        randSwapRows(matrix)
        randSwapColumns(matrix)
    return matrix

#test:
matrix = randSpecialMatrix(5)
for row in matrix: print(row)
print('-'*15)
print('row sums: ' + ', '.join(str(sum(row)) for row in matrix))
print('col sums: ' + ', '.join(str(sum(column)) for column in zip(*matrix)))

典型输出:

[3, 2, 2, 0, 3]
[3, 1, 0, 2, 3]
[4, 1, 3, 3, 4]
[2, 0, 3, 3, 4]
[0, 0, 2, 1, 1]
---------------
row sums: 10, 9, 15, 12, 4
col sums: 12, 4, 10, 9, 15

请注意,即使这是随机的,但在从0-4中满足所需属性的条目的所有5x5矩阵的集合中统一选择的意义上,它并不是真正随机的。如果没有随机生成矩阵的命中和未命中方法,直到得到这样的矩阵,我看不出任何方法来获得均匀分布。