Introdução
Você está sozinho em uma ilha. O restante da humanidade está morto ( provavelmente devido ao bug no código do user12345 ). A Horda de Piratas Zumbis chegou à sua ilha e são infinitas. É hora de chutar a bunda ou mascar chiclete, e todos estão sem chiclete.
Problema
Nosso cenário apocalíptico é descrito por 2 números inteiros em uma única linha, m
e n
. Na sua ilha, os postos avançados são numerados de 1 a m
. As seguintes n
linhas cada contêm três números inteiros, x
, y
, e z
, separados por um espaço. x
e y
são os IDs exclusivos de dois postos avançados e z
é o número de zumbis que serão encontrados no caminho entre eles.
Quando você viaja por um caminho, perde z
munição e mata z
zumbis. Se você seguir o mesmo caminho novamente, encontrará o mesmo número de zumbis, infelizmente. Todos os postos avançados geram +1 de munição cada vez que você percorre um caminho. Você começa com 100 munições no posto avançado 1. Todos os postos avançados começam com 0 munição. Você morre imediatamente se não houver um caminho para o qual sua munição seja maior que o número de zumbis nesse caminho, e o restante de sua munição for convertido em mortes. Essa é a sua posição final.
Escreva um programa que produza o número máximo de zumbis que você pode matar para um determinado cenário. Se você pode matar um número infinito de zumbis, basta imprimir x
.
Exemplo de entrada
5 6
1 2 4
2 3 4
3 1 4
2 4 10
2 5 10
1 1 50
Saída de exemplo
x
Suposições
- Um caminho estará entre dois postos avançados válidos. Ou seja, 1 <=
x
/y
<=m
- Se um caminho entre
x
ey
não estiver listado, não poderá ser percorrido - Um caminho é bidirecional
- 1
m
<<= 100 - 1
n
<<= 500 - A entrada deve ser fornecida por meio de stdin, lida de um arquivo ou aceita como um único argumento para o programa, e deve seguir exatamente o formato do exemplo
- O tempo de execução do seu programa pode ser arbitrariamente grande, mas deve ser determinadamente finito
O código com o menor número de caracteres vence!
1
começa com 0 munição? O gráfico é unidirecional?1->1
custa 49 munições e o ciclo1->2->3->1
custa 3 munições a longo prazo.Respostas:
Java ( menos grotesco:
841552913301)Está bem. Basicamente, estou envergonhado por ninguém ter enviado uma solução. Então, alguns dias atrás, comecei a tentar resolver esse problema, porque é ótimo. . Siga esse link para assistir ao meu progresso no GitHub.
Editar
Nova versão do solucionador, muito mais "golfada", com o verificador de ciclo corrigido conforme identificado pelo MT0. Ele também suporta rotas de avanço rápido, ajustáveis alterando a quantidade de memória disponível para a VM. Última edição do BIG : percebi que havia alguns outros pequenos erros de índice e otimizações prematuras, que resultaram em uma falha ao considerar um número bastante grande de tipos de vitórias. Então isso é corrigido, com cuidado. A nova versão é menor e abaixo. Para nossa rota de referência,
java -Xmx2GB ZombieHordeMin
faz o truque muito bem (esteja avisado, vai demorar um pouco).Factóide legal
Em uma reviravolta fascinante, existem MUITAS soluções no comprimento 24, e meu solucionador encontra uma diferente da MT0, mas idêntica em princípio, exceto pelo fato de começar visitando os outros postos conectados
1
. Fascinante! Totalmente contra a intuição humana, mas perfeitamente válida.Destaques da solução
Então aqui está o meu. É (parcialmente) jogado, b / c é um solucionador exponencial de força quase bruta. Uso um algoritmo IDDFS (primeira pesquisa aprofundada de aprofundamento iterativo), por isso é um ótimo solucionador geral que não pula, por isso resolve as duas partes da pergunta do OP, a saber:
Dê a ele energia, memória e tempo suficientes, e fará exatamente isso, até mapas de morte lenta. Passei mais tempo aprimorando esse solucionador e, embora mais possa ser feito, está um pouco melhor agora. Também integrei o conselho do MT0 sobre a melhor solução de zumbis infinitos e removi várias otimizações prematuras do meu verificador de vitórias que impediam a versão anterior de encontrá-lo, e agora encontro uma solução muito semelhante à que o MT0 descreveu.
Alguns outros destaques:
Eu instrumentei o algoritmo para torná-lo mais interessante de assistirRemovido para fins de golfe. Siga um dos links para o github para ver a versão não destruída.Também existem vários comentários, sinta-se à vontade para reimplementar a sua própria solução com base em minha abordagem ou me mostrar como isso deve ser feito!História do solucionador
O código (golfe)
Para o código (obtenha a versão não destruída aqui ou aqui ):
Obtenha o código do github aqui, para rastrear as alterações que eu fizer. Aqui estão alguns outros mapas que eu usei.
Exemplo de saída
Exemplo de saída para solução de referência:
Leia a saída da rota assim
step
::source
,route-to-get-here
-ammo
. Portanto, na solução acima, você a leria como:0
, no posto avançado1
com munição100
.1
, use a rota1
para chegar ao posto avançado3
com o fim da munição97
2
, use a rota1
para chegar ao posto avançado1
com o fim da munição95
Notas finais
Então, espero que eu tenha dificultado minha solução, mas POR FAVOR TENTE! Use-o contra mim, adicione algum processamento paralelo, melhor teoria gráfica, etc. Algumas coisas que eu acho que poderiam melhorar essa abordagem:
selecionar rotas mortas. Minha solução atual não "lembra" que uma rota específica é sem saída e precisa redescobri-la sempre. Seria melhor acompanhar o primeiro momento de uma rota em que a morte é certa e nunca progredir além dela.fez isso...Qualquer outra solução que troque memória por tempo ou permita evitar agressivamente as seguintes rotas sem saída.fiz isso também!fonte
Algumas notas abstratas sobre uma solução
Se eu tiver tempo, vou converter isso em um algoritmo ...
Para um dado gráfico
G
, existe um sub-gráfico conectadoG'
que contém a cidade1
. Se houver uma solução infinito então existirá uma sub-gráfico conectadoG''
deG'
que contémV
cidades eP
caminhos.Os caminhos
P
deG''
podem ser particionados de forma que{p}
contenha um caminho que possua um custo mínimo de todos os caminhosP
eP/{p}
sejam todos os outros caminhos (formando uma árvore de abrangência ou possivelmente um ciclo). Se assumirmos quep
não é uma borda circular (conectando as duas extremidades à mesma cidade), ela conectará duas cidades (v1
ev2
) e custarác
munição, então você (o sobrevivente) poderá atravessar de um ladov1
para o outrov2
com um custo total de2c
munição e isso aumentará a munição em todas as cidades em 2 (para um aumento total de2|V|
dentroG''
- algumas das quais serão coletadasv1
ev2
).Se você viajar de
v1
parav2
e de volta parav1
múltipla (m
) vezes e, em seguida, fazer uma viagem dev1
ao longo das bordasP/{p}
para visitar todas as outras que cidadesv1
ev2
antes de retornar aov1
e isso levan
caminhos para alcançar (onde|P/{p}| ≤ n ≤ 2|P/{p}|
já que você nunca precisará percorrer um caminho mais duas vezes) com um custo dek
e as cidades ganharão2m|V|
munição (novamente algumas das quais serão coletadas durante a travessia).Dado tudo isso, você pode saber se uma solução infinita é potencialmente possível se o custo
k + 2mc
for igual ou menor que a recompensa total2(m+n)|V|
.Há uma complexidade adicional para o problema:
1
para{p}
a primeira iteração e considerar esse custo; em
en
seja baixo o suficiente para não ficar sem munição antes de poder passar pela primeira iteração, pois a primeira iteração terá um custo mais alto do que as iterações subseqüentes).Isso leva a uma solução neutra em termos de custo de 24 caminhos para o exemplo da pergunta (os números são as cidades visitadas):
fonte