À partir d'une liste de points, trouvez le chemin le plus court qui visite tous les points et revient au point de départ.
Le problème des vendeurs ambulants est bien connu dans le domaine de l'informatique, de même que de nombreuses façons de le calculer / l'approcher. Il a été résolu pour de très grands groupes de points, mais certains des plus grands prennent plusieurs années CPU à terminer.
Ne vous brûlez pas avec la pomme de terre.
Hot Potato est un jeu où plus de 2 joueurs passent une "pomme de terre" en cercle pendant que la musique joue. Le but est de le passer rapidement au joueur suivant. Si vous tenez la pomme de terre lorsque la musique s'arrête, vous êtes absent.
L'objet de Hot Potato Salesman est:
Étant donné un ensemble de 100 points uniques , renvoyez ces points dans un meilleur ordre ( distance totale plus courte telle que définie plus bas ). Cela "passera" le problème au joueur suivant. Ils doivent l'améliorer et le passer au suivant, etc. Si un joueur ne peut pas l'améliorer, il est retiré et le jeu continue jusqu'à ce qu'il ne reste qu'un joueur.
Pour éviter que cela ne soit un concours "force-moi-un-chemin", il y a ces stipulations:
Vous ne pouvez pas prendre plus d' une minute pour passer la pomme de terre. Si vous n'avez pas trouvé et adopté une solution plus courte au bout d'une minute, vous êtes absent.
Vous ne pouvez pas modifier la position de plus de 25 points. Pour être exact, les
>= 75
points doivent être dans la même position que vous les avez reçus. Peu importe que ceux que vous décidez de changer, juste le montant que vous changez.
Lorsqu'il ne reste qu'un joueur, il est le vainqueur de cette partie et reçoit un point. Un tournoi se compose de 5*n
jeux, où n
est le nombre de joueurs. À chaque partie, le premier joueur sera mis en rotation et l'ordre des joueurs restants sera mélangé . Le joueur avec le plus de points à la fin est le vainqueur du tournoi. Si le tournoi se termine par une égalité pour la première place, un nouveau tournoi sera joué avec seulement ces concurrents. Cela continuera jusqu'à ce qu'il n'y ait pas d'égalité.
Le premier joueur de chaque partie recevra un ensemble de points sélectionnés de manière pseudo-aléatoire sans ordre particulier.
Les points sont définis comme une paire de x,y
coordonnées entières sur une grille cartésienne. La distance est mesurée en utilisant la distance de Manhattan , |x1-x2| + |y1-y2|
. Toutes les coordonnées se situeront dans la [0..199]
plage.
Contribution
L'entrée est donnée avec un seul argument de chaîne. Il sera composé de 201 entiers séparés par des virgules représentant le nombre de joueurs actuels ( m
) et 100 points:
m,x0,y0,x1,y1,x2,y2,...,x99,y99
L'ordre de ces points est le chemin actuel. La distance totale est obtenue en ajoutant la distance de chaque point au suivant ( dist(0,1) + dist(1,2) + ... + dist(99,0)
). N'oubliez pas de revenir au début lors du calcul de la distance totale!
Notez que ce m
n'est pas le nombre de joueurs qui ont commencé le jeu, c'est le nombre qui est encore en jeu.
Sortie
La sortie est donnée de la même manière que l'entrée, moins m
; une chaîne unique contenant des entiers séparés par des virgules représentant les points dans leur nouvel ordre.
x0,y0,x1,y1,x2,y2,...,x99,y99
Le programme de commande attendra la sortie pendant une minute seulement. Une fois la sortie reçue, il vérifiera que:
- la sortie est bien formée
- la sortie se compose de seulement et tous les 100 points présents dans l'entrée
>=75
les points sont dans leur position d'origine- la longueur du chemin est inférieure au chemin précédent
Si l'une de ces vérifications échoue (ou s'il n'y a pas de sortie), vous êtes absent et le jeu passe au joueur suivant.
Programme de contrôle
Vous pouvez trouver le programme de contrôle sur ce lien . Le programme de contrôle lui-même est déterministe et est affiché avec une graine factice de 1
. La graine utilisée lors de la notation sera différente, alors ne vous embêtez pas à essayer d'analyser l'ordre des tours / listes de points qu'elle crache.
La classe principale est Tourney
. L'exécution de ce tournoi fera un tournoi complet avec des candidats donnés comme arguments. Il recrache le vainqueur de chaque match et un décompte à la fin. Un exemple de tournoi avec deux SwapBots ressemble à:
Starting tournament with seed 1
(0) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 3
(0) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 4
(1) SwapBot wins a game! Current score: 5
(1) SwapBot wins a game! Current score: 6
(1) SwapBot wins a game! Current score: 7
(1) SwapBot wins a game! Current score: 8
Final Results:
Wins Contestant
2 (0) SwapBot
8 (1) SwapBot
Si vous souhaitez tester un seul jeu à la fois, vous pouvez exécuter la Game
classe à la place. Cela se déroulera un jeu avec les joueurs dans l'ordre donné comme arguments. Par défaut, il imprimera également un jeu par jeu montrant le lecteur actuel et la longueur du chemin.
Sont également inclus quelques joueurs de test: SwapBot
, BlockPermuter
et TwoSwapBot
. Les deux premiers ne seront pas inclus dans les courses de notation, alors n'hésitez pas à les utiliser et à en abuser pendant les tests. TwoSwapBot
sera inclus dans le jugement, et il n'est pas en reste, alors apportez votre A-game.
Recueil
Vous ne pouvez pas enregistrer les informations d'état et chaque tour est une exécution distincte de votre programme. La seule information que vous recevrez à chaque tour est l'ensemble de points.
Vous ne pouvez pas utiliser de ressources externes. Cela inclut les appels réseau et l'accès aux fichiers.
Vous ne pouvez pas utiliser les fonctions de bibliothèque conçues pour résoudre / aider avec le problème TSP ou ses variantes.
Vous ne pouvez en aucun cas manipuler ou interférer avec les autres joueurs.
Vous ne pouvez en aucun cas manipuler ou interférer avec le programme de contrôle ou les classes ou fichiers inclus.
Le multi-threading est autorisé.
Une soumission par utilisateur. Si vous soumettez plus d'une entrée, je n'entrerai que la première soumise. Si vous souhaitez modifier votre soumission, modifiez / supprimez l'original.
Le tournoi se déroulera sur Ubuntu 13.04, sur un ordinateur avec un processeur i7-3770K et 16 Go de RAM. Il ne sera pas exécuté sur une machine virtuelle. Tout ce que je perçois comme malveillant disqualifiera immédiatement la candidature actuelle et future que vous soumettez.
Toutes les entrées doivent être exécutables à partir de la ligne de commande avec un logiciel gratuit ( comme dans la bière ). Si j'ai des problèmes pour compiler / exécuter votre entrée, je demanderai de l'aide dans les commentaires. Si vous ne répondez pas ou que je ne parviens pas à le faire fonctionner, il sera disqualifié.
Résultats (22 mai 2014)
De nouveaux résultats sont arrivés! UntangleBot a battu la concurrence assez bien. TwoSwapBot a réussi sept victoires et SANNbot a également remporté une victoire. Voici un tableau de bord et un lien vers la sortie brute :
Wins Contestant
22 (2) ./UntangleBot
7 (0) TwoSwapBot
1 (5) SANNbot.R
0 (1) BozoBot
0 (3) Threader
0 (4) DivideAndConquer
À l' heure actuelle , UntangleBot a remporté la coche. Ne laissez pas cela vous décourager de participer, car je dirigerai le tournoi à mesure que de plus en plus de participants apparaîtront et modifier la réponse acceptée en conséquence.
la source
Réponses:
UntangleBot (anciennement NiceBot)
Un bot C ++ 11 qui utilise deux stratégies.
Dans un premier temps, il tentera de "démêler" le chemin si possible, en détectant les intersections entre les chemins qui sont plus proches de 25 points (car le démêlage implique de modifier tous les points intermédiaires).
Si la première stratégie échoue, elle échange aléatoirement des points pour trouver de meilleures distances jusqu'à ce qu'un meilleur chemin soit trouvé.
Ce bot bat systématiquement TwoSwapBot avec un ratio approximatif de cinq victoires pour une défaite dans mes tournois de test.
la source
SANNbot
(un robot de recuit simulé dans R )
Doit être appelé avec
Rscript SANNbot.R
.L'idée est relativement simple: chaque tour est une "étape de refroidissement" d'un recuit simulé avec le nombre de joueurs encore en jeu comme "température" (modifié par la distance actuelle sur 12000, soit à peu près la distance initiale). La seule différence avec un recuit simulé approprié est que j'ai vérifié que je ne permute pas plus de 25 éléments et que si j'ai utilisé 20 mouvements mais que la séquence résultante vaut plus que l'initiale, elle recommence.
la source
java Tourney "java Swapbot" "Rscript SANNbot.R"
et cela a semblé fonctionner.u
limites de vérification, cela ne se produit pas (et cela fonctionne beaucoup mieux). Bien que votre code semble assez simple, je ne connais pas les bizarreries de R, donc je ne peux pas dire si la logique est erronée. (la dernière version du contrôleur donnera des messages sur les raisons pour lesquelles un bot s'éteint lors de l'exécutionGame
, ce qui pourrait aider à identifier le problème)BozoBot
Utilise la logique complexe derrière Bozosort pour trouver un meilleur chemin. Cela ressemble à ceci.
BozoBot a maintenant été amélioré avec le multithreading ! Quatre serviteurs jonglent maintenant sans but avec des points jusqu'à ce qu'ils tombent sur une amélioration. Le premier à trouver une solution obtient un cookie!Apparemment, j'échoue au multithreading.
la source
new Thread(new Minion()).start()
TwoSwapBot
Une mise à niveau vers
SwapBot
, ce type vérifie chaque paire de swaps. Tout d'abord, il vérifie si un seul échange raccourcira le chemin. Si c'est le cas, il revient immédiatement. Sinon, il vérifie chacun pour voir si un autre échange le raccourcira. Sinon, il meurt.Bien que le chemin soit encore semi-aléatoire, il revient normalement dans environ 100 ms. S'il doit vérifier tous les 2 swaps (environ 25M), cela prend environ 20 secondes.
Au moment de la soumission, cela battait tous les autres concurrents dans les manches d'essai.
la source
Enfileur
Ce bot
410 morceaux de2510 pointsL'idée est de trouver la meilleure amélioration du chemin, afin que les autres bots échouent avec leur logique.
la source
println
pourprint
supprimer la nouvelle ligne à la fin de votre sortie. Sinon, il se bloque.println
pourprint
et fait le fil de comptage dynamique. Ça commence maintenant avec 10 threads ...Diviser et conquérir + Bot gourmand
REMARQUE: j'ai regardé votre code
Game
qui comprend les éléments suivants dans Game.parsePath:Cependant, il n'y a pas de
catch(NumberFormatException)
bloc, donc votre programme se bloquera probablement lorsqu'un programme de joueur sort une chaîne (comme démontré à la fin de lamain
méthode de mon programme ). Je vous conseille de résoudre ce problème, car les programmes peuvent générer des exceptions, des traces de pile ou similaires. Sinon, commentez cette ligne dans mon programme avant de l'exécuter.Retour au sujet
Cette implémentation (en Java) divise la liste de points en blocs de 25, espacés de manière aléatoire sur la liste. Ensuite, il crée des threads pour raccourcir le chemin entre les points de chaque bloc (d'où "Diviser pour régner"). Le thread principal surveille les autres et s'assure de présenter la solution la plus courte dans le délai imparti. Si un thread meurt avec ou sans solution, il démarre à nouveau un autre thread sur un bloc différent.
Chaque thread utilise l'algorithme "gourmand", qui commence sur un point aléatoire, va au point le plus proche et se répète jusqu'à ce que tous les points soient couverts (Par conséquent, "gourmand").
Remarques
Compilez et utilisez
java DivideAndConquer.class
pour exécuter.la source
<200
jetons avant d'essayer l'analyse. Encore mieux de le vérifier de toute façon.)
sur la ligne 19; changersubstr
poursubstring
le 38; initialiseridx
à quelque chose dans larun()
méthode.