Introducción
Estás solo en una isla. El resto de la humanidad está muerta ( probablemente debido al error en el código del usuario12345 ). La Horda Pirata Zombi ha llegado a tu isla, y son infinitas. Es hora de patear traseros o masticar chicle, y ya no tienes chicle.
Problema
Nuestro escenario del fin del mundo se describe por 2 enteros en una sola línea, m
y n
. En su isla hay puestos avanzados numerados de forma exclusiva del 1 al m
. Las siguientes n
líneas contienen cada uno tres números enteros, x
, y
, y z
, separados por un espacio. x
y y
son las identificaciones únicas de dos puestos avanzados, y z
es la cantidad de zombis que se encontrarán en el camino entre ellos.
Cuando recorres un camino, pierdes z
municiones y matas z
zombies. Si vuelves a recorrer el mismo camino, desafortunadamente encontrarás la misma cantidad de zombis. Todos los puestos avanzados generan +1 municiones cada vez que recorres un camino. Comienza con 100 municiones en el puesto avanzado 1. Todos los puestos avanzados comienzan con 0 municiones. Usted muere inmediatamente si no existe un camino para el cual su munición es mayor que la cantidad de zombis en ese camino, y el resto de su munición se convierte en muertes. Tal es tu posición final.
Escribe un programa que genere la cantidad máxima de zombies que puedes matar en un escenario determinado. Si puedes matar un número infinito de zombies, simplemente haz salir x
.
Entrada de ejemplo
5 6
1 2 4
2 3 4
3 1 4
2 4 10
2 5 10
1 1 50
Salida de ejemplo
x
Supuestos
- Una ruta será entre dos puestos avanzados válidos. Es decir 1 <=
x
/y
<=m
- Si un camino entre
x
yy
no está en la lista, no se puede recorrer - Un camino es bidireccional
- 1
m
<<= 100 - 1
n
<<= 500 - La entrada debe proporcionarse a través de stdin, leerse de un archivo o aceptarse como un argumento único para el programa, y debe seguir exactamente el formato del ejemplo
- El tiempo de ejecución de su programa puede ser arbitrariamente grande pero debe ser determinantemente finito
¡El código con la menor cantidad de caracteres gana!
1
comenzar con 0 munición? ¿Es el gráfico unidireccional?1->1
cuesta 49 municiones, y el ciclo1->2->3->1
cuesta 3 municiones a largo plazo.Respuestas:
Java ( menos grotesco:
841552913301)Okay. Básicamente, me da vergüenza que nadie haya presentado una solución. Hace unos días comencé a tratar de resolver este problema, b / c es genial. . Sigue ese enlace para ver mi progreso en él a través de GitHub.
Editar
Nueva versión de solucionador, mucho más "golfizada", con corrector de ciclo corregido identificado por MT0. También admite rutas de avance rápido, sintonizables cambiando la cantidad de memoria disponible para la VM. Última edición GRANDE : me di cuenta de que tenía algunos otros pequeños errores de índice y optimizaciones prematuras, lo que resultó en una falla al considerar una gran cantidad de tipos de victorias. Entonces eso está arreglado, con cuidado. La nueva versión es más pequeña y más abajo. Para nuestra ruta de referencia,
java -Xmx2GB ZombieHordeMin
el truco funciona bastante bien (ten en cuenta que tomará un tiempo).Factoid fresco
En un giro fascinante, hay MUCHAS soluciones con una longitud de 24, y mi solucionador encuentra una diferente de las MT0, pero idéntica en principio, excepto que comienza visitando los otros puestos avanzados conectados
1
. ¡Fascinante! Totalmente contraria a la intuición humana, pero perfectamente válida.Soluciones destacadas
Así que aquí está el mío. Es (parcialmente) golfizado, b / c es un solucionador exponencial de fuerza casi bruta. Utilizo un algoritmo IDDFS (profundización iterativa de primera búsqueda de profundidad), por lo que es un gran solucionador general que no se salta, por lo que resuelve ambas partes de la pregunta del OP, a saber:
Dale suficiente poder, memoria y tiempo, y hará exactamente eso, incluso mapas de muerte lenta. Pasé un poco más de tiempo mejorando este solucionador, y aunque se puede hacer más, ahora es un poco mejor. También integré el consejo de MT0 sobre la mejor solución de zombies infinitos, y eliminé varias optimizaciones prematuras de mi comprobador de victorias que impedían que la versión anterior lo encontrara, y ahora de hecho encuentro una solución muy similar a la que MT0 describió.
Algunos otros puntos destacados:
He instrumentado el algoritmo para que sea más interesante verRemoved con fines de golf. Siga uno de los enlaces a github para ver la versión sin golf.También hay una serie de comentarios, así que siéntase libre de volver a implementar su propia solución basándose en mi enfoque, ¡o muéstreme cómo debe hacerse!Historia del solucionador
El código (golfizado)
En el código (obtenga la versión no protegida aquí o aquí ):
Obtenga el código de github aquí, para rastrear cualquier cambio que realice. Aquí hay algunos otros mapas que utilicé.
Ejemplo de salida
Ejemplo de salida para la solución de referencia:
Lea la salida de la ruta de esta manera
step
::source
,route-to-get-here
-ammo
. Entonces, en la solución anterior, lo leería como:0
, en el puesto avanzado1
con munición100
.1
, usa la ruta1
para llegar al puesto avanzado3
con munición final97
2
, usa la ruta1
para llegar al puesto avanzado1
con munición final95
Notas de cierre
Por lo tanto, espero haber hecho que mi solución sea más difícil de superar, ¡pero POR FAVOR INTENTE! Úselo en mi contra, agregue un procesamiento paralelo, una mejor teoría de gráficos, etc. Un par de cosas que creo podrían mejorar este enfoque:
descartar rutas muertas. Mi solución actual no "recuerda" que una ruta en particular tiene un punto muerto y tiene que redescubrirla cada vez. Sería mejor hacer un seguimiento del primer momento en una ruta en la que la muerte es segura, y nunca avanzar más allá.hice esto...Cualquier otra solución que cambie la memoria por tiempo o que permita evitar agresivamente seguir las rutas sin salida.hizo esto también!fuente
Algunas notas abstractas sobre una solución
Si tengo tiempo, convertiré esto en un algoritmo ...
Para un gráfico dado
G
, existe un sub-gráfico conectadoG'
que contiene la ciudad1
. Si hay una solución infinito entonces existirá una sub-gráfico conectadoG''
deG'
que contieneV
pueblos yP
caminos.Las rutas
P
deG''
pueden dividirse de manera tal que{p}
contengan una ruta que tenga un costo mínimo de todas las rutasP
y queP/{p}
sean todas las demás rutas (formando un árbol de expansión o posiblemente un ciclo). Si asumimos quep
no es una ventaja bucle (que conecta los dos extremos a la misma ciudad), se conectará dos ciudades (v1
yv2
) y tiene costoc
municiones entonces (el sobreviviente) puede entonces tener travesía dev1
av2
y de vuelta a un costo total de2c
municiones y esto aumentará la munición en todos los pueblos en 2 (para un aumento total de2|V|
dentroG''
, algunos de los cuales se habrán recogido dev1
yv2
).Si usted viaja de
v1
av2
y de vuelta alv1
múltiple (m
) veces y luego toma un viaje dev1
largo de los bordesP/{p}
para visitar todos los pueblos distintosv1
yv2
antes de regresar av1
lo cual requiere den
caminos para lograr (donde|P/{p}| ≤ n ≤ 2|P/{p}|
ya que nunca debería tener que recorrer un camino más que dos veces) con un costo dek
y las ciudades obtendrán2m|V|
municiones (de nuevo, algunas de las cuales se habrán recogido durante el recorrido).Dado todo esto, puede decir si una solución infinita es potencialmente posible si el costo
k + 2mc
es igual o menor que la recompensa total2(m+n)|V|
.Hay una complejidad adicional al problema en que:
1
hasta{p}
la primera iteración y tenga en cuenta este costo; ym
yn
sean lo suficientemente bajos como para no quedarse sin municiones antes de poder pasar por la primera iteración, ya que la primera iteración tendrá un costo mayor que las iteraciones posteriores).Esto lleva a una solución de costo neutral de 24 caminos para el ejemplo en la pregunta (los números son las ciudades visitadas):
fuente