Gere com eficiência todas as partições de vetor


12

Uma partição de vetor está dividindo um vetor em uma série de vetores, de modo que sua soma seja a original. Aqui estão algumas partições:

[3, 1, 2] = [3, 1, 2]
[3, 1, 2] = [0, 0, 1] + [0, 0, 1] + [0, 1, 0] + [1, 0, 0] + [2, 0, 0]
[3, 1, 2] = [1, 1, 2] + [2, 0, 0]

Aqui, a adição de vetores é feita em elementos. Uma partição válida não contém nenhum vetor com números inteiros negativos ou o vetor zero.

Agora, o desafio é escrever um programa ou função que gere todas as partições de vetores possíveis, considerando um vetor de destino. Isso pode parecer relativamente fácil ...

... mas há uma torção. Se o vetor de entrada tiver tamanho L e a maior partição gerada tiver elementos M, você não poderá usar mais que memória O (L * M).

Você pode assumir que um número inteiro usa memória O (1). Isso significa que você deve gerar as partições à medida que as gera. Além disso, você deve gerar cada partição exatamente uma vez. Por exemplo, estas são a mesma partição:

[3, 1, 2] = [3, 0, 2] + [0, 1, 0]
[3, 1, 2] = [0, 1, 0] + [3, 0, 2]

Se você produziu, sua resposta é inválida.


Todas as partições para [3, 2]:

[3, 2]
[0, 1] + [3, 1]
[0, 1] + [0, 1] + [3, 0]
[0, 1] + [0, 1] + [1, 0] + [2, 0]
[0, 1] + [0, 1] + [1, 0] + [1, 0] + [1, 0]
[0, 1] + [1, 0] + [2, 1]
[0, 1] + [1, 0] + [1, 0] + [1, 1]
[0, 1] + [1, 1] + [2, 0]
[0, 2] + [3, 0]
[0, 2] + [1, 0] + [2, 0]
[0, 2] + [1, 0] + [1, 0] + [1, 0]
[1, 0] + [2, 2]
[1, 0] + [1, 0] + [1, 2]
[1, 0] + [1, 1] + [1, 1]
[1, 1] + [2, 1]
[1, 2] + [2, 0]

Para testar sua resposta, execute-o [3, 2, 5, 2]. Ele deve gerar 17939 partições, todas somadas [3, 2, 5, 2]e únicas (você pode testar a exclusividade classificando primeiro cada partição lexicograficamente).


O código mais curto em bytes vence.

Respostas:


3

Python 2, 289 bytes

Algoritmo simples de força bruta. Trata a lista inteira como um número na base max(input)+1( b) e verifica cada "número" no intervalo [0, b**(L*M))para ver se:

  1. Somas para a quantidade correta
  2. Está em ordem alfabética (garante exclusividade)

Se a lista corresponder a esses critérios, o programa a emitirá com todos os vetores totalmente zero removidos.

Uso de memória

A maior estrutura de dados que eu uso neste programa é uma lista duplamente aninhada, um comprimento de lista que Mcontém o comprimento mínimo Lpara fornecer O(L*M)memória.

Para minhas outras estruturas de dados, tenho 3 entradas globais O(3), 1 comprimento de lista L( O(L)), 1 comprimento de matriz M( O(M)) e uma cópia da maior matriz ao gerar ( O(L*M)).

No total, isso me dá um uso de memória O(2*L*M + L + M + 3)que simplifica O(L*M), preenchendo os critérios.

Complexidade do tempo

Sendo um algoritmo de força bruta, esse algoritmo é extremamente lento. Para que o loop while saia, o int final na matriz precisa ser b-1. O loop precisa executar os b**(L*M)tempos antes que isso aconteça.

Além disso, cada vez que a lista é executada, é necessário verificar as duas condições e imprimir a lista na pior das hipóteses, usando L*M+L+Miterações. Isso simplifica para dar uma geral O(L*M * b**(L*M)). Tentei testar meu programa [3, 2, 5, 2], mas desisti após 45 minutos.

Programa de golfe

v=input()
L=len(v)
M=sum(v)
b=max(v)
R=range
t=[L*[0]for i in R(M)]
def A(l,i):
 if i<L*M-1and~-b<l[i/L][i%L]:A(l,i+1)
 l[i/L][i%L]=-~l[i/L][i%L]%-~b
while t[-1][-1]<b:
 if v==[sum(q[i]for q in t)for i in R(L)]and all(`t[i]`>=`t[i+1]`for i in R(M-1)):print[x for x in t if[0]*L!=x]
 A(t,0)

Talvez eu consiga jogar um pouco mais, especialmente a parte do incremento. Código ungolfed chegando.


Definitivamente não é a eficiência que eu estava esperando quando eu postei esta pergunta, mas eu acho que tecnicamente resolve o problema :)
orlp
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.