Comme vous avez dit qu'une solution non optimale ne vous dérangeait pas, j'ai pensé réutiliser votre fonction initiale et ajouter un moyen de trouver un bon arrangement de départ pour votre liste initiale. s
Votre fonction initiale :
def pigeon_hole(s):
a = [[], [], []]
sum_a = [0, 0, 0]
for x in s:
i = sum_a.index(min(sum_a))
sum_a[i] += x
a[i].append(x)
return map(sum, a)
C'est un moyen de trouver un ordre initial raisonnable pour votre liste, il fonctionne en créant des rotations de votre liste dans l'ordre trié et trié inversé. La meilleure rotation est trouvée en minimisant l'écart-type, une fois que la liste a été classée :
def rotate(l):
l = sorted(l)
lr = l[::-1]
rotation = [np.roll(l, i) for i in range(len(l))] + [np.roll(lr, i) for i in range(len(l))]
blocks = [pigeon_hole(i) for i in rotation]
return rotation[np.argmin(np.std(blocks, axis=1))] # the best rotation
import random
print pigeon_hole(rotate([random.randint(0, 20) for i in range(20)]))
# Testing with some random numbers, these are the sums of the three sub lists
>>> [64, 63, 63]
Bien que cela puisse être optimisé davantage, c'est assez rapide : 0,0013s pour 20 numéros. Je fais une comparaison rapide avec la réponse de @Mo Tao, en utilisant la méthode suivante a = rotate(range(1, 30))
# This method
a = rotate(range(1, 30))
>>> [[29, 24, 23, 18, 17, 12, 11, 6, 5], [28, 25, 22, 19, 16, 13, 10, 7, 4, 1], [27, 26, 21, 20, 15, 14, 9, 8, 3, 2]]
map(sum, a)
# Sum's to [145, 145, 145] in 0.002s
# Mo Tao's method
>>> [[25, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [29, 26, 20, 19, 18, 17, 16], [28, 27, 24, 23, 22, 21]]
# Sum's to [145, 145, 145] in 1.095s
Cette méthode semble également trouver la solution optimale dans de nombreux cas, bien que cela ne soit probablement pas le cas dans tous les cas. Je teste cette mise en œuvre 500 fois en utilisant une liste de 30 nombres contre la réponse de Mo Tao, et je compare si les sous-listes donnent la même quantité :
c = 0
for i in range(500):
r = [random.randint(1, 10) for j in range(30)]
res = pigeon_hole(rotate(r))
d, e = sorted(res), sorted(tao(r)) # Comparing this to the optimal solution by Mo Tao
if all([k == kk] for k, kk in zip(d, e)):
c += 1
memory = {}
best_f = pow(sum(s), 3)
best_state = None
>>> 500 # (they do)
J'ai pensé faire une mise à jour avec une version plus optimisée de ma fonction ici :
def rotate2(l):
# Calculate an acceptable minimum stdev of the pigeon holed list
if sum(l) % 3 == 0:
std = 0
else:
std = np.std([0, 0, 1])
l = sorted(l, reverse=True)
best_rotation = None
best_std = 100
for i in range(len(l)):
rotation = np.roll(l, i)
sd = np.std(pigeon_hole(rotation))
if sd == std:
return rotation # If a min stdev if found
elif sd < best_std:
best_std = sd
best_rotation = rotation
return best_rotation
Le principal changement est que la recherche d'un bon ordonnancement s'arrête une fois qu'une rotation appropriée a été trouvée. De plus, seule la liste triée à l'envers est recherchée, ce qui ne semble pas modifier le résultat. En synchronisant cela avec
print timeit.timeit("rotate2([random.randint(1, 10) for i in range(30)])", "from __main__ import rotate2, random", number=1000) / 1000.
entraîne une augmentation importante de la vitesse. Sur mon ordinateur actuel rotate
prend environ 1,84 ms et rotate2
prend environ 0.13ms, soit une accélération d'environ 14x. Pour comparaison, l'implémentation de 's a pris environ 0.99ms sur ma machine.
6 votes
Mon cerveau n'est pas encore tout à fait prêt, mais j'essaie de décider si c'est essentiellement le problème de sac à dos qui est NP dur.
0 votes
@JonathonReinhart c'est plus proche du problème des sous-ensembles, mais comme le PO ne cherche pas une solution parfaite, il peut utiliser un de ses algorithmes d'approximation.
1 votes
Mais "Le résultat n'est pas si mauvais, il ne garantit pas une solution optimale." On dirait qu'il cherche une solution optimale.
7 votes
Votre problème est une généralisation du problème de la somme des sous-ensembles, mais il existe un algorithme en temps pseudo-polynomial et une approximation facile (très bonne) pour ce problème.
1 votes
@JonathonReinhart, pas besoin d'être optimal, mais ce serait bien si c'était le cas. Tant que cela produit un très bon résultat.
1 votes
Merci @Saeed, oui fr.m.wikipedia.org/wiki/Sous-ensemble_sum_problem est complet NP. L'efficacité de votre algorithme avide dépend probablement du nombre / de la gamme de vos valeurs d'entrée. (Si vous avez beaucoup de petites valeurs avec lesquelles travailler, cela devrait bien "s'équilibrer").
4 votes
Au fait,
sorted(s, reverse=True)
n'a aucun effet commesorted
renvoie une nouvelle liste.1 votes
Notez également que mémorisation est souvent utilisé dans les solutions de programmation dynamique et est facile à ajouter à une fonction en Python.
0 votes
Ce qu'a dit DeepSpace, Pour trier une liste en place, utilisez son
.sort
méthode. POUR INFO,sorted
fonctionne en copiant son arg itérable dans une liste, puis en appelant la fonction.sort
sur cette liste. Il est donc généralement préférable d'utiliser.sort
plutôt quesorted
quand vous le pouvez.0 votes
@PM2Ring, merci pour vos commentaires. En général, je veux écrire rapidement ce que j'ai en tête pour montrer ce que j'ai essayé. En fait, je n'ai pas encore fait la vraie mise en œuvre. J'ai juste besoin de voir plus de possibilités d'abord :D
0 votes
@invisal Quelle est la longueur de la liste d'entrée ?
S
?0 votes
@Fomalhaut, la longueur du S est d'environ 10 à 20. Pas grand.
0 votes
@Fomalhaut, joli coup, mais je réédite la fonction que je veux optimiser.
1 votes
Quelle est l'étendue de la gamme des nombres dans S ? Une méthode de programmation dynamique qui prend O(Somme(S)^3) temps est simple.
0 votes
@MoTao, le SUM(S) est autour de 100~150.
2 votes
Cet article sur le partitionnement des nombres à voies multiples pourrait vous intéresser (en particulier, la section 4, le partitionnement des nombres séquentiels (SNP)) : aaai.org/ocs/index.php/IJCAI/IJCAI-09/paper/viewFile/625/705
0 votes
@SaeedAmiri, MartijnPieters Le double est loin de susciter l'intérêt ou la variété des réponses à cette question. Je pense que la marquer comme un doublon est une erreur.
0 votes
@, C'est un doublon, même s'il a de meilleurs votes et une meilleure présentation ici.
1 votes
@SaeedAmiri, MartijnPieters si cette question est supprimée, SO perd du contenu de qualité. Sans parler de tout le travail fourni par les personnes qui ont contribué. Si cette question a "de meilleurs votes et une meilleure présentation", comme le dit Saeed, pourquoi ne pas marquer l'option autre comme un doublon alors ? Je n'aime pas ce genre de modération arbitraire - "dupliqué" devrait signifier "ne contient aucune nouvelle information" plutôt que de suivre une directive sans réfléchir à ce que cela signifie pour le contenu du SO, et pour les personnes qui contribuent à faire du SO ce qu'il est.
0 votes
@, Cette question n'a pas du tout d'informations supplémentaires. Il y a juste une image qui la rend plus belle. Les réponses à l'autre question sont soit meilleures que les réponses ici, soit au moins aussi bonnes que les réponses ici (ici, les réponses sont en fait comme la résolution d'un devoir). En outre, si vous lisez ces règles dans la définition des doublons, vous pouvez comprendre que le terme "doublon" ne signifie pas répéter la question, mais signifie que la question a déjà reçu une réponse ailleurs ! Il se peut même que vous posiez une question d'apparence totalement différente, mais à laquelle il a déjà été répondu quelque part. Cela n'apporte donc rien de nouveau.
0 votes
@SaeedAmiri, (cc MartijnPieters) J'ai utilisé le mot "meilleur" parce que vous l'avez fait. Je pense que certaines des réponses ici ajoutent un contenu différent à l'OS que les réponses à l'autre question. Et votre commentaire sur la directive de l'OS concernant les doublons illustre exactement mon propos, " duplicate devrait signifier ne contient aucune information nouvelle ou différente plutôt que de suivre une directive sans réfléchir à ce que cela signifie pour le contenu de la SO et pour les personnes qui contribuent à faire de la SO ce qu'elle est".
0 votes
@, il est toujours possible de déplacer ces réponses vers l'autre question. Mais si vous avez d'autres discussions à ce sujet, vous pouvez toujours en discuter dans la méta.
1 votes
Il ne s'agit pas d'une duplication de la question précédemment liée. Ici : "L'ordre du nombre et le nombre d'éléments dans ce tableau n'a pas d'importance". Voilà : "Je veux les grouper avec un ordre"