Découvrez les combinaisons de nombres d'un ensemble d'ajouter jusqu'à un total de
J'ai été chargé d'aider certains comptables résoudre un problème commun, ils ont donné une liste de transactions et un dépôt total, les transactions qui font partie de la caution? Par exemple, dire que j'ai cette liste de nombres:
1.00
2.50
3.75
8.00
Et je sais que mon total de la caution est 10.50
, je peux facilement voir qu'il est fait de la 8.00
et 2.50
transaction. Toutefois, étant donné une centaine de transactions et un dépôt de garantie en millions de dollars, il devient rapidement beaucoup plus difficile.
Dans les tests de force brute solution (qui prend beaucoup trop de temps à être pratique), j'avais deux questions:
- À une liste d'environ 60 numéros, il semble trouver une douzaine ou plus de combinaisons pour n'importe quel montant raisonnable. Je m'attendais à une combinaison unique de satisfaire ma totale, ou peut-être un peu de possibilités, mais il semble toujours être une tonne de combinaisons. Est-il un math principe qui explique pourquoi il en est? Il semble que, étant donné une collection de nombres aléatoires de même une taille moyenne, vous pouvez trouver une multitude de combinaisons qui ajoute jusqu'à juste au sujet de tout montant total que vous souhaitez.
- J'ai construit une force brute solution au problème, mais c'est de O(n!), et grandit vite hors de contrôle. Outre l'évident raccourcis (à l'exclusion de nombre plus grand que le total d'eux-mêmes), il est un moyen de raccourcir le temps de calculer ce?
De détails sur ma super lent) solution:
La liste des montants détail est trié du plus grand au plus petit, puis le processus suivant s'exécute de manière récursive:
- Prendre l'élément suivant dans la liste et voir si de l'ajouter à votre total en cours d'exécution rend votre total de correspondre à la cible. Si elle le fait, mettre de côté la chaîne actuelle, comme un match. Si il tombe à court de votre cible, de l'ajouter à votre total en cours d'exécution, le retirer de la liste des montants détail, et ensuite appeler ce processus à nouveau
De cette manière, il exclut le plus grand nombre rapidement, la coupe de la liste vers le bas pour seulement le nombre de besoins à prendre en compte. Cependant, il est toujours n! et les grandes listes semblent ne jamais se terminer, donc je suis intéressé par tous les raccourcis que je pourrais être en mesure de prendre de la vitesse, je pense que même coupe 1 nombre de la liste permettrait de réduire le temps de calcul dans la moitié.
Merci pour votre aide!
double
a 64 bits, et vos chiffres sont issus d'un petit sous-ensemble de cette, de sorte qu'il n'est pas vraiment une surprise que à 60 éléments il existe de nombreuses solutions, il y en a 2^60 sous-ensembles dont les sommes de la carte dans le double.n! est faux, c'est 2^n.
OriginalL'auteur SqlRyan | 2010-10-21
Vous devez vous connecter pour publier un commentaire.
Ce cas particulier du problème de sac-à-Dos est appelé Somme De Sous-Ensemble.
OriginalL'auteur Falk Hüffner
Version C#
configuration de test:
code:
résultats:
Si les sous-totaux sont répétées, il n'y aura semblent être les résultats (l'effet désiré). En réalité, vous aurez probablement besoin d'utiliser la sous-total Tupled avec une pièce d'identité, de sorte que vous pouvez rapporter à vos données.
OriginalL'auteur Dan
Si je comprends votre problème correctement, vous disposez d'un ensemble de transactions, et vous seul souhait est de savoir lequel d'entre eux pourrait avoir été pris en compte dans une totale. Donc, si il existe 4 opérations, puis il y a 2^4 = 16 ensembles possibles pour l'inspecter. Ce problème est, pour 100 transactions possibles, l'espace de recherche a 2^100 = 1267650600228229401496703205376 combinaisons possibles pour la recherche. Pour 1000 transactions potentielles dans le mélange, elle pousse jusqu'à un total de
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
ensembles que vous devez tester. La force Brute ne sera guère une solution viable sur ces problèmes.
Au lieu de cela, utiliser un solveur qui peut gérer sac à dos problèmes. Mais même alors, je ne suis pas sûr que vous pouvez générer une énumération complète de toutes les solutions possibles sans une certaine variation de la force brute.
La seule autre sous-ensemble est zéro le cas, où aucune transaction n'est utilisé. Si l'on exclut le cas de la recherche, puis nous avons seulement 1 moins d'éléments dans l'ensemble, pour 2^n-1 règle à prendre en compte. Pour n grand, la différence semble insignifiant pour moi.
OriginalL'auteur
Il y a un bon marché Excel Add-in qui permet de résoudre ce problème: SumMatch
OriginalL'auteur Albert
Le Solveur de microsoft Excel Addin comme posté plus sur superuser.com a une solution (si vous avez Excel) https://superuser.com/questions/204925/excel-find-a-subset-of-numbers-that-add-to-a-given-total
OriginalL'auteur Omar Shahine
Son genre de sac à Dos 0-1 problème est NP-complet et peut être résolu par programmation dynamique en temps polynomial.
http://en.wikipedia.org/wiki/Knapsack_problem
Mais à la fin de l'algorithme, vous devez également vérifier que la somme est ce que tu voulais.
OriginalL'auteur vinothkr
En fonction de vos données, vous pouvez regarder les cents partie de chaque transaction. Comme dans votre exemple, vous savez que 2.50 doit faire partie de la total car il est le seul ensemble de non-zéro cent des transactions qui s'ajoutent aux 50.
OriginalL'auteur Jon Snyder
Pas une super solution efficace mais heres une mise en œuvre en coffeescript
combinations
retourne toutes les combinaisons possibles des éléments danslist
et puis
find_components
l'utilise pour déterminer le nombre d'ajouter jusqu'àtotal
Heres un exemple
qui renvoie
[ 7.2, 2, 4.1 ]
OriginalL'auteur Loourr