Genera eficientemente todas las particiones vectoriales


12

Una partición de vector está dividiendo un vector en una serie de vectores de modo que su suma sea la original. Aquí hay un par de particiones:

[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]

Aquí la adición de vectores se realiza por elementos. Una partición válida no contiene ningún vector con enteros negativos, o el vector todo cero.

Ahora el desafío es escribir un programa o función que genere todas las particiones de vectores posibles dado un vector de destino. Esto puede sonar relativamente fácil ...

...Pero hay un giro. Si el vector de entrada tiene el tamaño L, y la partición más grande que genera tiene elementos M, no puede usar más que la memoria O (L * M).

Puede suponer que un entero usa la memoria O (1). Esto significa que debe generar las particiones a medida que las genera. Además de eso, solo debe generar cada partición exactamente una vez. Por ejemplo, estas son la misma partición:

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

Si tuviera que dar salida a ambos, su respuesta no es válida.


Todas las particiones 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 probar tu respuesta, ejecútala [3, 2, 5, 2]. Debería generar 17939 particiones, todas las cuales suman [3, 2, 5, 2], y que son todas únicas (puede probar la unicidad ordenando primero cada partición lexicográficamente).


El código más corto en bytes gana.

Respuestas:


3

Python 2, 289 bytes

Algoritmo de fuerza bruta simple. Trata la lista completa como un número en base max(input)+1( b) y verifica cada "número" en el rango [0, b**(L*M))para ver si:

  1. Sumas a la cantidad correcta
  2. Está en orden alfabético (asegura la unicidad)

Si la lista coincide con estos criterios, el programa la muestra con todos los vectores sin ceros eliminados.

Uso de memoria

La estructura de datos más grande que uso en este programa es una lista doblemente anidada, una longitud de lista que Mcontiene la longitud de liss Lpara dar O(L*M)memoria.

Para mis otras estructuras de datos, tengo 3 entradas globales O(3), 1 longitud de lista L( O(L)), 1 longitud de matriz M( O(M)) y una copia de la matriz más grande al generar ( O(L*M)).

En total, esto me da un uso de memoria O(2*L*M + L + M + 3)que se simplifica O(L*M), cumpliendo los criterios.

Complejidad de tiempo

Al ser un algoritmo de fuerza bruta, este algoritmo es extremadamente lento. Para que el ciclo while salga, el int final en la matriz debe ser b-1. El ciclo debe ejecutarse b**(L*M)antes de que eso suceda.

Además, cada vez que se ejecuta la lista, debe verificar ambas condiciones e imprimir la lista en el peor de los casos, utilizando L*M+L+Miteraciones. Esto se simplifica para dar un total O(L*M * b**(L*M)). Traté de probar mi programa [3, 2, 5, 2], pero me di por vencido después de 45 minutos.

Programa de golf

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)

Podría ser capaz de jugar al golf un poco más, especialmente la parte de incremento. Se acerca un código sin golf.


Definitivamente no es la eficiencia que esperaba cuando publiqué esta pregunta, pero supongo que técnicamente resuelve el problema :)
orlp
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.