Générez efficacement toutes les partitions vectorielles


12

Une partition vectorielle divise un vecteur en une série de vecteurs de telle sorte que leur somme soit l'original. Voici quelques partitions:

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

Ici, l'ajout de vecteur se fait par élément. Une partition valide ne contient aucun vecteur avec des nombres entiers négatifs ou le vecteur tout à zéro.

Maintenant, le défi consiste à écrire un programme ou une fonction qui génère toutes les partitions vectorielles possibles étant donné un vecteur cible. Cela peut sembler relativement facile ...

... mais il y a une torsion. Si le vecteur d'entrée a la taille L et que la plus grande partition qu'il génère a M éléments, vous ne pouvez pas utiliser plus de mémoire O (L * M).

Vous pouvez supposer qu'un entier utilise la mémoire O (1). Cela signifie que vous devez générer les partitions lors de leur génération. De plus, vous ne devez sortir chaque partition qu'une seule fois. Par exemple, ce sont la même partition:

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

Si vous deviez sortir les deux, votre réponse n'est pas valide.


Toutes les partitions pour [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]

Pour tester votre réponse, exécutez-la [3, 2, 5, 2]. Il doit générer 17939 partitions, qui se résument toutes à [3, 2, 5, 2], et qui sont toutes uniques (vous pouvez tester l'unicité en triant d'abord chaque partition lexicographiquement).


Le code le plus court en octets gagne.

Réponses:


3

Python 2, 289 octets

Algorithme de force brute simple. Traite la liste entière comme un nombre dans base max(input)+1( b) et vérifie chaque "nombre" dans la plage [0, b**(L*M))pour voir s'il:

  1. Somme au montant correct
  2. Est dans l'ordre alphabétique (garantit l'unicité)

Si la liste correspond à ces critères, le programme la renvoie avec tous les vecteurs entièrement nuls supprimés.

Utilisation de la mémoire

La plus grande structure de données que j'utilise dans ce programme est une liste doublement imbriquée, une longueur de liste Mcontenant une longueur liss Lpour donner de la O(L*M)mémoire.

Pour mes autres structures de données, j'ai 3 entrées globales O(3), 1 longueur de liste L( O(L)), 1 longueur de tableau M( O(M)) et une copie du plus grand tableau lors de la sortie ( O(L*M)).

Au total, cela me donne une utilisation de la mémoire O(2*L*M + L + M + 3)qui simplifie O(L*M), remplissant les critères.

Complexité temporelle

Étant un algorithme de force brute, cet algorithme est extrêmement lent. Pour que la boucle while se ferme, le dernier entier du tableau doit être b-1. La boucle doit s'exécuter b**(L*M)avant que cela ne se produise.

En outre, chaque fois que la liste s'exécute, elle doit vérifier les deux conditions et imprimer la liste dans le pire des cas, à l'aide d' L*M+L+Mitérations. Cela simplifie pour donner un global O(L*M * b**(L*M)). J'ai essayé de tester mon programme [3, 2, 5, 2], mais j'ai abandonné après 45 minutes.

Programme 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)

Je pourrais peut-être jouer un peu plus au golf, en particulier la partie incrémentale. Code non golfé à venir.


Certainement pas l'efficacité que j'espérais quand j'ai posté cette question, mais je suppose que cela résout techniquement le problème :)
orlp
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.