introduction
Vous êtes seul sur une île. Le reste de l'humanité est mort ( probablement à cause du bogue dans le code de user12345 ). La Horde de pirates zombies a atteint votre île et ils sont infinis. Il est temps de botter le cul ou de mâcher du chewing-gum, et vous êtes tous sortis du chewing-gum.
Problème
Notre scénario apocalyptique est décrit par 2 entiers sur une seule ligne, m
et n
. Sur votre île se trouvent des avant-postes numérotés de 1 à m
. Ce qui suit les n
lignes contiennent chacune trois entiers, x
, y
, et z
, séparés par un espace. x
et y
sont les identifiants uniques de deux avant-postes, et z
est le nombre de zombies qui seront rencontrés sur le chemin entre eux.
Lorsque vous voyagez sur un chemin, vous perdez des z
munitions et vous tuez des z
zombies. Si vous suivez à nouveau le même chemin, vous rencontrerez malheureusement le même nombre de zombies. Tous les avant-postes génèrent +1 munition à chaque fois que vous parcourez un chemin. Vous commencez avec 100 munitions à l'avant-poste 1. Tous les avant-postes commencent par 0 munition. Vous mourez immédiatement s'il n'existe aucun chemin pour lequel vos munitions sont supérieures au nombre de zombies sur ce chemin, et le reste de vos munitions est converti en tués. Telle est votre position finale.
Écrivez un programme qui génère le nombre maximum de zombies que vous pouvez tuer pour un scénario donné. Si vous pouvez tuer un nombre infini de zombies, sortez simplement x
.
Exemple d'entrée
5 6
1 2 4
2 3 4
3 1 4
2 4 10
2 5 10
1 1 50
Exemple de sortie
x
Hypothèses
- Un chemin sera entre deux avant-postes valides. Soit 1 <=
x
/y
<=m
- Si un chemin entre
x
ety
n'est pas répertorié, il ne peut pas être parcouru - Un chemin est bidirectionnel
- 1
m
<<= 100 - 1
n
<<= 500 - L'entrée doit être fournie via stdin, lue dans un fichier ou acceptée comme seul argument du programme, et elle doit suivre exactement le format de l'exemple
- La durée d'exécution de votre programme peut être arbitrairement grande mais doit être déterminée de façon déterminante
Le code avec le moins de caractères gagne!
1
commence-t-il par 0 munitions? Le graphique est-il non directionnel?1->1
coûte 49 munitions et le cycle1->2->3->1
coûte 3 munitions à long terme.Réponses:
Java ( moins grotesque:
841552913301)D'accord. Fondamentalement, je suis gêné, personne n'a soumis de solution. Il y a quelques jours, j'ai commencé à essayer de résoudre ce problème, b / c c'est super. . Suivez ce lien pour voir mes progrès à ce sujet via GitHub.
modifier
Nouvelle version du solveur, beaucoup plus "golfée", avec correcteur de cycle corrigé identifié par MT0. Il prend également en charge les itinéraires d'avance rapide, ajustables en modifiant la quantité de mémoire disponible pour la machine virtuelle. Dernière modification BIG : j'ai réalisé que j'avais quelques autres petites erreurs d'index et des optimisations prématurées, ce qui s'est traduit par un échec à considérer un assez grand nombre de types de gains. C'est donc fixe, soigneusement. La nouvelle version est à la fois plus petite et inférieure. Pour notre itinéraire de référence,
java -Xmx2GB ZombieHordeMin
fait très bien l'affaire (attention, cela prendra un certain temps).Cool factoid
Dans une tournure fascinante, il y a BEAUCOUP de solutions à la longueur 24, et mon solveur en trouve une différente de MT0, mais identique en principe, sauf qu'elle commence par visiter les autres avant-postes connectés
1
. Fascinant! Totalement contre l'intuition humaine, mais parfaitement valable.Points saillants de la solution
Voici donc le mien. C'est (partiellement) joué au golf, b / c c'est un solveur exponentiel, presque de force brute. J'utilise un algorithme IDDFS (première profondeur d'approfondissement itératif), c'est donc un excellent solveur général qui ne saute pas, donc il résout les deux parties de la question de l'OP, à savoir:
Donnez-lui suffisamment de puissance, de mémoire et de temps, et il fera exactement cela, même des cartes à mort lente. J'ai passé un peu plus de temps à améliorer ce solveur, et même si plus peut être fait, c'est un peu mieux maintenant. J'ai également intégré les conseils de MT0 sur la meilleure solution de zombies infinis, et supprimé plusieurs optimisations prématurées de mon vérificateur de gains qui empêchaient la version précédente de la trouver, et maintenant je trouve en fait une solution très similaire à celle décrite par MT0.
Quelques autres points saillants:
J'ai instrumenté l'algorithme pour le rendre plus intéressant à regarderSupprimé à des fins de golf. Suivez l'un des liens vers github pour voir la version non golfée.Il y a également un certain nombre de commentaires, alors n'hésitez pas à réimplémenter pour votre propre solution en s'appuyant sur mon approche, ou montrez-moi comment cela doit être fait!Histoire du solveur
Le code (golfé)
Passons au code (obtenez la version non golfée ici ou ici ):
Obtenez le code de github ici, pour suivre toutes les modifications que j'apporte. Voici quelques autres cartes que j'ai utilisées.
Exemple de sortie
Exemple de sortie pour la solution de référence:
Lisez la sortie de l'itinéraire comme ceci
step
::source
,route-to-get-here
-ammo
. Donc, dans la solution ci-dessus, vous le liriez comme:0
, à l'avant-poste1
avec des munitions100
.1
, utilisez l'itinéraire1
pour vous rendre à l'avant-poste3
avec des munitions de fin97
2
, utilisez l'itinéraire1
pour vous rendre à l'avant-poste1
avec des munitions de fin95
Notes de clôture
J'espère donc avoir rendu ma solution plus difficile à battre, mais S'IL VOUS PLAÎT ESSAYEZ! Utilisez-le contre moi, ajoutez un traitement parallèle, une meilleure théorie des graphes, etc. Quelques éléments que je pense pourraient améliorer cette approche:
abattre les routes mortes. Ma solution actuelle ne "se souvient" pas qu'un itinéraire particulier est sans issue et doit le redécouvrir à chaque fois. Il serait préférable de garder une trace du premier moment sur une route dont la mort est certaine, et de ne jamais progresser au-delà.a fait ça ...Toute autre solution qui échange la mémoire contre du temps ou permet d'éviter de manière agressive de suivre des voies sans issue.a fait ça aussi!la source
Quelques notes abstraites sur une solution
Si j'ai le temps, je le convertirai en algorithme ...
Pour un graphe donné,
G
il existe alors un sous-graphe connectéG'
qui contient la ville1
. S'il y a une solution infinie alors il existera un sous-graphe connexeG''
deG'
qui contient desV
villes et desP
chemins.Les chemins
P
d' accèsG''
peuvent être partitionnés de manière à{p}
contenir un chemin d'accès qui a alors un coût minimal de tous les chemins d'accèsP
etP/{p}
constitue tous les autres chemins (formant un arbre couvrant ou éventuellement un cycle). Si nous partons du principe quep
n'est pas un bord en boucle (reliant les deux extrémités de la même ville), il reliera deux villes (v1
etv2
) et a coûté desc
munitions alors vous (le survivant) peut alors traverser dev1
àv2
et revenir à un coût total de2c
munitions et cela augmentera les munitions dans toutes les villes de 2 (pour une augmentation totale de l'2|V|
intérieurG''
- dont certaines auront été collectées auprès dev1
etv2
).Si vous voyagez de
v1
àv2
et revenir àv1
plusieurs (m
fois, puis prendre un voyage de) lev1
long des bordsP/{p}
à visiter toutes les villes autres quev1
etv2
avant de revenir àv1
ce qui prend desn
chemins pour atteindre (où|P/{p}| ≤ n ≤ 2|P/{p}|
puisque vous ne devriez jamais avoir à traverser une voie plus plus de deux fois) avec un coût dek
et les villes gagneront des2m|V|
munitions (dont une partie aura été récupérée lors de la traversée).Compte tenu de tout cela, vous pouvez savoir si une solution infinie est potentiellement possible si le coût
k + 2mc
est égal ou inférieur à la récompense totale2(m+n)|V|
.Il y a une complexité supplémentaire au problème en ce que:
1
à{p}
la première itération et prendre en compte ce coût; etm
etn
sont suffisamment bas pour ne pas manquer de munitions avant de pouvoir passer par la première itération car la première itération aura un coût plus élevé que les itérations suivantes).Cela conduit à une solution neutre en termes de coûts sur 24 voies pour l'exemple de la question (les chiffres sont les villes visitées):
la source