Algorithm 如果行和是列和的排列,如何生成矩阵?

Algorithm 如果行和是列和的排列,如何生成矩阵?,algorithm,math,matrix,Algorithm,Math,Matrix,对于给定的整数N,我想生成一个NxN阶矩阵,其中行和是列和的某种排列 例如: 3 023 401 130 行和为5、5、4 列和是5,5,4 两者都是彼此的排列 如何为任意给定的N生成这样的矩阵 附言: 我知道对角矩阵,对称矩阵会在这里工作,像这样的矩阵 3 100 01 0110 但是我想做一个随机矩阵。一种获得随机矩阵的方法如下: 首先创建一个随机对称矩阵。这样一个矩阵的行和等于列和 请注意,如果交换任意两行,则其行和将被置换,但其列和将被单独保留。类似地,如果交换任意两列,则其列和将被置换

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

例如:

3
023
401
130

行和为5、5、4
列和是5,5,4

两者都是彼此的排列

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

附言: 我知道对角矩阵,对称矩阵会在这里工作,像这样的矩阵

3
100
01
0110


但是我想做一个随机矩阵。

一种获得随机矩阵的方法如下:

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

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

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

请注意,尽管这看起来是随机的,但从所有5x5矩阵集合中均匀选择满足所需属性的条目(0-4)的意义上讲,这并不是真正的随机。在得到这样一个矩阵之前,如果没有一种随机生成矩阵的方法,我看不到任何获得均匀分布的方法

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

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

你想重复多少次就重复多少次,直到你觉得已经足够混乱为止。例如,您可以决定重复n²次

最后,您可以洗牌行,以增加随机性:行和现在对应于列和的排列

下面是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]]
我在行洗牌之前使用了此检查,以确保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)

对进入矩阵的数字有任何限制吗?不是这样的。考虑到它是任何整数。是的,我想到了这个解决方案,这就是为什么我改变了我之前给出的例子。这个解决方案隐藏了原始的对称矩阵,但我更感兴趣的是知道我们是否可以生成类似于我上面给出的东西。谢谢你的回答。如果你交换矩阵的前两行,你会得到一个对称矩阵。在任何情况下,如果你对解决方案有一个约束,那么你应该清楚地说明这个约束,而不是让它隐式存在。如果你看的是我在问题中添加的示例,它不能转换为对称矩阵。另外,如果你注意到我在PS部分清楚地提到了一个例子,我知道这样的矩阵是可能的解决方案,但我真的很抱歉,如果你不允许的话。这看起来有点随机。谢谢你的回答。