从1到90创建一个唯一数字的M*N矩阵。

3

我希望在Python中开发一个算法,根据特定的规则/条件,随机填充数字1到90之间的18x9矩阵。

规则

#1 - Maintain an array of 18x9 between 1 and 90. 
#2 - First column contains 1-10, second column contains 11-20, etc.
#3 - Each row must have 5 numbers. Other columns should be set to 0.
#4 - Numbers must be arranged in ascending order from top to bottom in a column

我目前为止做了什么?

import numpy as np

columns = 9
rows = 18
n_per_row = 5

matrix = np.zeros((rows, columns), dtype=int)

# Keep track of available places at each row.
available_places = {k: n_per_row for k in range(rows)}

# Shuffle order in which we fill the columns.
col_order = np.arange(columns)
np.random.shuffle(col_order)

for column in col_order:
    # Indices of available rows.
    indices = [c for c in available_places if available_places[c]]
    
    # Sample which row to use of the available.
    indices = np.random.choice(indices, size=min(len(indices), 10), replace=False)
    # print(indices)
    
    # Values for this column.
    col_values = np.random.choice(list(np.arange(1, 10+1)), size=min(len(indices), 10), replace=False) + column*10
    
    # Fill in ascending order.
    matrix[sorted(indices), column] = sorted(col_values)

    for idx in indices:
        available_places[idx] -= 1
print(matrix)

    

结果

 [[ 0  0  0 31  0 51  0 71 81]
 [ 1 11  0  0  0 52 61 72  0]
 [ 0  0 21 32 41  0 62 73  0]
 [ 0  0 22 33  0  0  0 74 82]
 [ 0 12 23  0 42  0 63  0 83]
 [ 2 13 24 34  0 53  0  0  0]
 [ 3  0  0  0 43 54 64  0 84]
 [ 4  0  0  0 44 55 65  0 85]
 [ 5 14  0  0 45  0 66  0 86]
 [ 6  0 25 35 46  0  0 75  0]
 [ 7 15 26 36  0  0  0  0 87]
 [ 8 16  0  0 47  0  0 76 88]
 [ 0 17 27  0 48  0  0 77 89]
 [ 0 18  0  0 49 56 67 78  0]
 [ 9  0 28 39  0 57  0 79  0]
 [ 0  0 29  0 50 58 68 80  0]
 [ 0 19 30 40  0 59 69  0  0]
 [10 20  0  0  0 60 70  0 90]]

预期结果:https://images.meesho.com/images/products/56485141/snksv_512.jpg

更新了问题! - PSN
1
请明确一下:18 x 9 是指18行乘以9列?每行应该恰好有5个数字吗?(因为您说“不能有更多”,但听起来您的意思是每个18行中恰好有5个数字,总共有90个)。此外,请明确一点,从1到90的每个数字都只使用一次?因此,我们有一个额外的限制条件,即第一列有9个数字,最后一列有11个数字,其他每列有10个数字?“第一列包含1-10,第二列包含11-20,依此类推。”这似乎并不完全描述示例输出,例如第二列中有“10”。 - Karl Knechtel
你是否愿意使用numpy来完成这个任务? - Mad Physicist
@PSN,我删除了我的答案,因为它是基于我误解的旧要求构建的。 - user2246849
你的图片显示第一列是1-9,第二列是10-19,以此类推。你确定你的规则#2是对的吗? - pirela
显示剩余5条评论
1个回答

1

根据4个规则的最终结果如下:
每行有5个值
每列有10个值,从1、11、21等按升序排列
(请注意,这些规则不适用于像图中所示的宾果游戏)

============ final matrix ===============
--------------------------------
[1, 11, 21, 31, 41, 0, 0, 0, 0]
[2, 12, 0, 32, 42, 0, 61, 0, 0]
[0, 13, 0, 33, 0, 0, 62, 71, 81]
[3, 0, 0, 34, 0, 0, 63, 72, 82]
[0, 0, 22, 0, 0, 51, 64, 73, 83]
[4, 14, 23, 35, 0, 52, 0, 0, 0]
[5, 0, 24, 0, 43, 53, 0, 0, 84]
[6, 15, 0, 36, 44, 54, 0, 0, 0]
[7, 0, 0, 37, 0, 0, 65, 74, 85]
[0, 0, 0, 0, 45, 55, 66, 75, 86]
[8, 16, 25, 0, 0, 0, 67, 76, 0]
[0, 0, 26, 0, 46, 56, 0, 77, 87]
[9, 17, 0, 0, 0, 0, 68, 78, 88]
[10, 18, 0, 0, 0, 57, 0, 79, 89]
[0, 19, 27, 38, 47, 0, 0, 80, 0]
[0, 20, 28, 39, 48, 58, 0, 0, 0]
[0, 0, 29, 0, 49, 59, 69, 0, 90]
[0, 0, 30, 40, 50, 60, 70, 0, 0]
--------------------------------   

原则:
首先建立一个矩阵,用0和1作为未来值的占位符。
在矩阵中每个单元格随机设置0或1,但要考虑每行和每列中1的数量以满足约束条件。
由于随机分配可能会导致早期没有足够的1,因此在第一次尝试时无法同时满足两个约束条件。程序会自动重试并跟踪每次尝试进行观察。(我的测试中最多循环10次,平均不超过3次)
一旦得到一个令人满意的0和1的矩阵,就将每个列对应的值替换为1。
解决方案:

import random
# #1 - Maintain an array of 18x9 (between 1 and 90)
maxRow = 18
maxCol = 9


# #2 - First column contains 1-10, second column contains 11-20, etc.
# ie first column 1 start from 1 and have 10 entries, column 2 start from 11 and have 10 entries, etc. 
origins = [i*10 +1 for i in range(maxCol)]  #[1, 11, 21, 31, 41, 51, 61, 71, 81]
maxInCol = [10 for i in range(maxCol)]      #[10, 10, 10, 10, 10, 10, 10, 10, 10]

# comfort  : display matrix
def showMatrix():
    print('--------------------------------')
    for row in range(len(matrix)):
        print(matrix[row])
    print('--------------------------------')

# comfort : count #values in a col 
def countInCol(col):
    count = 0
    for row in range(maxRow):
        count+=matrix[row][col]
    return count     

# verify the rules of 5 per row and 10 per cols 
def verify():
    ok = True
    showMatrix()
    # count elements in a col
    for col in range(maxCol):
        count = 0
        for row in range(maxRow):
            count+= matrix[row][col]
        if(count!= maxInCol[col]): 
            print ('*** wrong # of elements in col {0} : {1} instead of {2}'.format(col, count,maxInCol[col]))
            ok = False
    # count elements in a row 
    for row in range(maxRow):
        count = 0
        for col in range(maxCol):
            count+= matrix[row][col]
        if(count!=5): 
            print('***** wrong # of elements in row {0} : {1}'.format(row, count))
            ok = False
    if (not ok): print( '********************************************')
    return ok 

# -- main ----
# need to iterate in case of no more value to complete a col 
tour = 1
maxTour = 100 #security limit 
while True:
    # prepare a matrix of rows of cols of 0 
    matrix = [[0 for i in range(maxCol)] for i in range(18)]
    # begin to fill some places with 1 instead of 0 
    for row in range(maxRow):
        count = 0
        for col in range(maxCol):
            if (count==5): break   # line is already full with 5 elt
            # random a 0 or 1 
            placeHolder = random.choice([0,1])
            #  if the remaining cols of this row needs to be 1 to complete at 5/row
            if (5-count) == (maxCol-col): 
                placeHolder = 1 # must complete the row 
            else: 
                inCol = countInCol(col)
                # 10 places max in col 
                if (inCol)==maxInCol[col]: placeHolder = 0 # this col is full
                # constraint : if the remaining rows of this col need to be 1 to complete the expected 10 values
                if(maxRow-row) == (maxInCol[col]-inCol): placeHolder = 1
            matrix[row][col] = placeHolder
            count+= placeHolder
    #-------- some case are not correct . prog loops 

    if verify(): 
        print(' ok after {0} loop(s)'.format(tour))
        break
    # security infinite loop 
    if (tour>=maxTour): break
    tour +=1

# now replace the placeholders by successive values per col 
print('\n============ final matrix ===============')
for row in range(maxRow):
    for col in range(maxCol):
        if  matrix[row][col]==1:
            matrix[row][col] = origins[col]
            origins[col]+=1

showMatrix()

HTH


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接