Résumé
Compte tenu de l' entrée k
, trouver une partition d'entiers 1
à n
en k
sous - ensembles sans somme pour le plus grand n
possible dans les 10 minutes.
Contexte: numéros Schur
Un ensemble A
est sans somme si son auto-somme A + A = { x + y | x, y in A}
n'a aucun élément en commun avec lui.
Pour chaque entier positif, k
il y a un plus grand entier S(k)
tel que l'ensemble {1, 2, ..., S(k)}
peut être partitionné en k
sous-ensembles sans somme. Ce numéro est appelé le k ème numéro Schur (OEIS A045652 ).
Par exemple S(2) = 4
,. Nous pouvons partitionner en {1, 2, 3, 4}
tant que {1, 4}, {2, 3}
, et c'est la partition unique en deux sous-ensembles sans somme, mais nous ne pouvons pas maintenant ajouter un 5
à l' une ou l'autre partie.
Défi
Écrivez un programme déterministe qui fait ce qui suit:
- Prendre un entier positif
k
en entrée - Ecrire l'horodatage Unix actuel sur stdout
- Génère une séquence de partitions de
1
àn
enk
sous-ensembles sans somme à augmentern
, en suivant chaque séquence avec l'horodatage Unix actuel.
Le gagnant sera le programme qui imprime une partition pour la plus grande n
dans les 10 minutes sur mon ordinateur lorsqu'il est saisi 5
. Les liens seront rompus par le temps le plus rapide pour trouver une partition pour le plus grand n
, en moyenne sur trois exécutions: c'est pourquoi la sortie devrait inclure des horodatages.
Détails importants:
- J'ai Ubuntu Precise, donc si votre langue n'est pas prise en charge, je ne pourrai pas la noter.
- J'ai un processeur Intel Core2 Quad, donc si vous voulez utiliser le multithreading, il est inutile d'utiliser plus de 4 threads.
- Si vous souhaitez que j'utilise des indicateurs ou une implémentation de compilateur particuliers, documentez-le clairement dans votre réponse.
- Vous ne devez pas casse spéciale votre code pour gérer l'entrée
5
. - Vous n'êtes pas obligé de générer chaque amélioration trouvée. Par exemple, pour l'entrée,
2
vous ne pouvez générer que la partitionn = 4
. Cependant, si vous ne produisez rien dans les 10 premières minutes, je noterai celan = 0
.
la source
n=59
et le tri par le plus grand nombre de nombres autorisés moins que le nombrenextN
donnén=64
. Le tri selon la longueur de la liste des numéros non autorisés (qui peut avoir des répétitions) conduit très rapidement à unn=30
motif élégant .Tue Nov 10 00:44:25 2015
), mais j'ai vun=92
en moins de 2 secondes.ctime
surtime
parce que la sortie était plus jolie quandtime
était exactement ce que j'aurais pris.n=121
. oOPython 3, 121, <0,001 s
Grâce à l'heuristique améliorée grâce à Martin Buttner, nous n'avons même pas besoin d'aléatoire.
Production:
Code:
Python 3, 112
Trier par somme des 2 premiers éléments + biais
J'ai copié la structure de données d'El'endia Starman, qui se compose d'une liste de paires, où le premier élément de la paire est les éléments de ce compartiment et le second les sommes de ce compartiment.
Je commence par la même approche «suivre les sommes disponibles». Mon heuristique de tri est simplement la somme des deux plus petits éléments d'une liste donnée. J'ajoute également un petit biais aléatoire pour essayer différentes possibilités.
Chaque itération place simplement chacun le nouveau numéro dans la première poubelle avalible, semblable à un gourmand aléatoire. Une fois que cela échoue, il redémarre simplement.
la source
Java 8, n =
142144Dernière sortie:
Effectue une recherche aléatoire prédéfinie répartie sur 4 threads. Lorsqu'il ne parvient pas à trouver une partition pour y entrer,
n
il essaie de libérer de l'espace pourn
une partition à la fois en en vidant le plus possible dans les autres partitions.modifier: peaufiné l'algorithme pour libérer de l'espace pour
n
, également ajouté la possibilité de revenir à un choix précédent et de choisir à nouveau.note: la sortie n'est pas strictement déterministe car il y a plusieurs threads impliqués et ils peuvent finir par mettre à jour le meilleur
n
trouvés jusqu'à présent dans un ordre brouillé; le score final de 144 est cependant déterministe et est atteint assez rapidement: 30 secondes sur mon ordinateur.Le code est:
la source
C, gourmand aléatoire, n = 91
Juste pour fournir une solution de base, cela se répète
n
, en gardant une trace des bacs et de leurs sommes et ajouten
à un bac aléatoire où il n'apparaît pas encore comme une somme. Il se termine une foisn
apparaît dans toutes lesk
sommes, et si le résultatn
était meilleur que toute tentative précédente, l'imprime dans STDOUT.L'entrée
k
est fournie via un argument de ligne de commande. Le maximum possiblek
est actuellement codé en dur à 10 car j'étais trop paresseux pour ajouter une allocation de mémoire dynamique, mais cela pourrait être corrigé facilement.Je suppose que je pourrais aller à la recherche d'une meilleure graine maintenant, mais cette réponse n'est probablement pas particulièrement compétitive de toute façon, alors meh.
Voici la partition pour
n = 91
:Et enfin, voici le code:
la source
n=91
, trouvé en 138 secondes. Si nécessaire pour briser l'égalité, je vais retimer pour éviter les grosses erreurs dues à une charge CPU différente.C ++, 135
Ajoute le n suivant à un sous-ensemble choisi au hasard. Si ce n'est pas possible, il supprime les nombres aléatoires des sous-ensembles et les ajoute à d'autres dans l'espoir que cela permet d'ajouter n quelque part.
J'ai prototypé cela en awk, et parce que cela semblait prometteur, je l'ai traduit en C ++ pour l'accélérer. L'utilisation d'un
std::set
devrait même l'accélérer davantage.Sortie pour n = 135 (après environ 230 secondes sur ma [vieille] machine)
Je n'ai pas revérifié la validité, mais ça devrait aller.
la source
Python 3, aléatoire gourmand, n = 61
Dernière sortie:
Celui-ci utilise effectivement le même algorithme que celui de Martin Büttner , mais je l'ai développé indépendamment.
Il y a des
k
bacs qui contiennent à la fois les chiffres et les chiffres qui ne peuvent plus y entrer. À chaque profondeur de l'itération (c'est essentiellement une recherche en profondeur d'abord), l'ordre des cases est mélangé et le numéro suivant (nextN
) est (séquentiellement) placé dans les cases qui peuvent le prendre, puis va plus loin. S'il n'y en a pas, il revient, sauvegardant une étape.la source
Python, n = 31
Ok, donc ce n'est visiblement pas un gagnant, mais je sentais que ça appartenait de toute façon. J'ai pris la liberté de ne pas inclure d'horodatage, car il se termine instantanément, et comme ce n'est pas un vrai concurrent.
Tout d'abord, notez que la somme de deux nombres impairs quelconques est paire, afin que nous puissions vider tous les nombres impairs dans le premier bloc. Puis, comme tous les nombres restants sont pairs, nous pouvons les diviser par 2. Encore une fois, nous pouvons jeter tous les nombres impairs résultants dans le deuxième bloc (après les avoir multipliés par 2), diviser les nombres restants par 2 (c'est-à-dire , par 4 au total), jetez les impairs dans le troisième bloc (après les avoir multipliés par 4), et ainsi de suite ... Ou, pour mettre les mots que vous comprenez, nous mettons tous les nombres dont l'ensemble le moins significatif bit est le premier bit du premier bloc, tous les nombres dont le bit défini le moins significatif est le deuxième bit du deuxième bloc, etc.
Pour les blocs k , nous rencontrons des problèmes une fois que nous atteignons n = 2 k , car le bit le moins significatif de n est
le ( k + 1) -ème bit, qui ne correspond à aucun bloc. En d' autres termes, ce système fonctionne jusqu'à
à n = 2 k - 1. Ainsi, alors que pour k = 5 , nous obtenons seulement un maigre n = 31 , ce nombre croît de façon exponentielle avec k . Il établit également que S ( k ) ≥ 2 k - 1 (mais nous pouvons en fait trouver une meilleure limite inférieure que cela assez facilement.)
Pour référence, voici le résultat pour k = 5:
la source
[1], [2,3], [4,5,6,7], ...
, ce qui est probablement plus simple, juste avec l'ordre inverse des bits et des blocs. Il est facile de voir comment celui-ci peut être étendu.