Перечислить все возможные матрицы с ограничениями

Я пытаюсь перечислить все возможные матрицы размером r на r с некоторыми ограничениями.

  1. Суммы строк и столбцов должны быть указаны в порядке убывания возрастания.
  2. Начиная с левого верхнего элемента по главной диагонали, каждое подмножество строк и столбцов из этой записи должно состоять из комбинаций с заменами от 0 до значения в этой верхней левой записи (включительно).
  3. Суммы строк и столбцов должны быть меньше или равны заранее заданному значению n.
  4. Основная диагональ должна располагаться в порядке возрастания.

Важное примечание: мне нужно, чтобы каждая комбинация где-то сохранялась или, если она написана на C ++, выполнялась через несколько других функций после их нахождения

r и n - значения в диапазоне от 2 до 100.

Я пробовал рекурсивный способ сделать это вместе с итеративным, но продолжаю зацикливаться на отслеживании сумм столбцов и строк вместе со всеми данными в управляемом смысле.

Я приложил свою последнюю попытку (которая еще далека от завершения), но могу дать вам представление о том, что происходит.

Функция first_section(): правильно строит нулевую строку и нулевой столбец, но кроме этого у меня ничего не получается.

Мне нужно больше, чем толчок, чтобы добиться успеха, логика - это боль в заднице, и она поглощает меня целиком. Мне нужно, чтобы это было написано на Python или C ++.

import numpy as np
from itertools import combinations_with_replacement
global r
global n 
r = 4
n = 8
global myarray
myarray = np.zeros((r,r))
global arraysums
arraysums = np.zeros((r,2))

def first_section():
    bigData = []
    myarray = np.zeros((r,r))
    arraysums = np.zeros((r,2))
    for i in reversed(range(1,n+1)):
        myarray[0,0] = i
        stuff = []
        stuff = list(combinations_with_replacement(range(i),r-1))
        for j in range(len(stuff)):
            myarray[0,1:] = list(reversed(stuff[j]))
            arraysums[0,0] = sum(myarray[0,:])
            for k in range(len(stuff)):
                myarray[1:,0] = list(reversed(stuff[k]))
                arraysums[0,1] = sum(myarray[:,0])
                if arraysums.max() > n:
                    break
                bigData.append(np.hstack((myarray[0,:],myarray[1:,0])))
                if printing: print 'myarray \n%s' %(myarray)
    return bigData

def one_more_section(bigData,index):
    newData = []
    for item in bigData:
        if printing: print 'item = %s' %(item)
        upperbound = int(item[index-1])    # will need to have logic worked out
        if printing: print 'upperbound = %s' % (upperbound)
        for i in reversed(range(1,upperbound+1)):
            myarray[index,index] = i
            stuff = []
            stuff = list(combinations_with_replacement(range(i),r-1))
            for j in range(len(stuff)):
                myarray[index,index+1:] = list(reversed(stuff[j]))
                arraysums[index,0] = sum(myarray[index,:])
                for k in range(len(stuff)):
                    myarray[index+1:,index] = list(reversed(stuff[k]))
                    arraysums[index,1] = sum(myarray[:,index])
                    if arraysums.max() > n:
                        break
                    if printing: print 'index = %s' %(index)
                    newData.append(np.hstack((myarray[index,index:],myarray[index+1:,index])))
                    if printing: print 'myarray \n%s' %(myarray)
    return newData

bigData = first_section()
bigData = one_more_section(bigData,1)

Возможная матрица могла бы выглядеть так: r = 4, n> = 6

|3 2 0 0| = 5
|3 2 0 0| = 5
|0 0 2 1| = 3
|0 0 0 1| = 1
 6 4 2 2

person KevinShaffer    schedule 10.06.2013    source источник
comment
когда вы говорите «не по возрастанию», вы имеете в виду, что хотя бы один не должен быть в порядке возрастания или что ни один из них не может быть? например. можно сказать, что {0,1,2,3,4,5,7,6} находится в порядке возрастания, начиная с 6 ‹7, или можно сказать, что он находится в порядке возрастания, начиная с 2› 1.   -  person Andrew W    schedule 10.06.2013
comment
Я имею в виду невозрастание в том смысле, что у меня может быть 2,2,0 или что-то вроде 2,1,0, но не 0,2,2. Имеет ли это смысл?   -  person KevinShaffer    schedule 11.06.2013


Ответы (1)


Вот решение в numpy и python 2.7. Обратите внимание, что все строки и столбцы расположены в невозрастающем порядке, потому что вы только указали, что они должны быть комбинациями с заменой, а не их сортировкой (а создание комбинаций является самым простым с отсортированными списками).

Код можно несколько оптимизировать, сохраняя суммы строк и столбцов в качестве аргументов вместо их повторного вычисления.

import numpy as np

r = 2 #matrix dimension
maxs = 5 #maximum sum of row/column

def generate(r, maxs):
    # We create an extra row and column for the starting "dummy" values. 
    # Filling in the matrix becomes much simpler when we do not have to treat cells with
    # one or two zero indices in special way. Thus, we start iteration from the
    # (1, 1) index. 

    m = np.zeros((r + 1, r + 1), dtype = np.int32)
    m[0] = m[:,0] = maxs + 1

    def go(n, i, j):
        # If we completely filled the matrix, yield a copy of the non-dummy parts.
        if (i, j) == (r, r):
            yield m[1:, 1:].copy()
            return

        # We compute the next indices in row major order (the choice is arbitrary).
        (i2, j2) = (i + 1, 1) if j == r else (i, j + 1)

        # Computing the maximum possible value for the current cell.
        max_val = min(
            maxs - m[i, 1:].sum(), 
            maxs - m[1:, j].sum(),
            m[i, j-1], 
            m[i-1, j])

        for n2 in xrange(max_val, -1, -1):
            m[i, j] = n2
            for matrix in go(n2, i2, j2):
                yield matrix

    return go(maxs, 1, 1) #note that this is a generator object

# testing 
for matrix in generate(r, maxs):
    print
    print matrix

Если вы хотите иметь все допустимые перестановки в строках и столбцах, приведенный ниже код должен работать.

def generate(r, maxs):
    m = np.zeros((r + 1, r + 1), dtype = np.int32)
    rows = [0]*(r+1) # We avoid recomputing row/col sums on each cell.
    cols = [0]*(r+1)
    rows[0] = cols[0] = m[0, 0] = maxs

    def go(i, j):
        if (i, j) == (r, r):
            yield m[1:, 1:].copy()
            return

        (i2, j2) = (i + 1, 1) if j == r else (i, j + 1)

        max_val = min(rows[i-1] - rows[i], cols[j-1] - cols[j])

        if i == j: 
            max_val = min(max_val, m[i-1, j-1])
        if (i, j) != (1, 1):
            max_val = min(max_val, m[1, 1])

        for n in xrange(max_val, -1, -1):
            m[i, j] = n
            rows[i] += n
            cols[j] += n 
            for matrix in go(i2, j2):
                yield matrix
            rows[i] -= n
            cols[j] -= n 

    return go(1, 1) 
person András Kovács    schedule 10.06.2013
comment
Это фантастика, я не ожидал столь быстрого ответа на такой исчерпывающий ответ. Спасибо! - person KevinShaffer; 11.06.2013
comment
РЕДАКТИРОВАТЬ: Я удалил минимальную проверку диагонального элемента, так как понял, что это лишнее после проверок строки / столбца. - person András Kovács; 11.06.2013
comment
Хотя у меня есть один вопрос / комментарий. Это не полностью исчерпывает возможности, поскольку диагональные элементы кажутся ограниченными элементами вверху и слева. И он должен ограничиваться только верхним левым элементом, если это имеет смысл. [[6,4,2], [3,5,0] [,, *]] никогда не произойдет, потому что 5 в элементе [1,1] будет ограничиваться 3 и 4 вверху и слева от него. - person KevinShaffer; 11.06.2013
comment
Что ж, во втором ограничении вы требовали, чтобы все строки и столбцы были комбинациями с заменой. Я истолковал это как необходимость включения только всех комбинаций, а не всех перестановок; это означает, что мы делаем выбор (и несколько произвольный), чтобы пропустить некоторые из них. Но получить все перестановки также должно быть довольно легко. Думаю, я внесу правку в ответ для этого. - person András Kovács; 12.06.2013
comment
... Но я просто понял, что до сих пор я полностью игнорировал эту строку, а суммы столбцов также должны быть в не возрастающем порядке. Кажется, это так, хотя в коде моего ответа. Это несколько усложняет версию с генерацией перестановок. - person András Kovács; 12.06.2013
comment
Верно, с тех пор (как мне кажется) я нашел ответ, просто адаптировав то, что вы написали, но если у вас есть идея, не стесняйтесь отправлять ее. Я очень доволен тем, что вы дали поработать - person KevinShaffer; 12.06.2013