Solução Informática - Nível Avançado - Semana 34

Solução escrita por Enzo Dantas

Conhecimento prévio necessário:

Esse é um problema clássico e, portanto, abre espaço para diversas ideias e otimizações. Sendo assim, essa solução focará apenas na solução esperada.

Intuição

Primeiramente, imagine o que aconteceria se, de algum jeito, deixássemos o algoritmo de Dijkstra continuar rodando depois de ter achado todos os menores caminhos. O algoritmo de Dijkstra original acha o menor caminho e depois não visita mais aquele vértice, mas, tendo em mente como a ideia gulosa do Dijkstra funciona, se deixássemos ele visitar os vértices mais vezes, faz sentido pensar que ele primeiro visitaria um certo vértice com o menor caminho, depois com o segundo menor caminho, depois com o terceiro, e assim por diante.

Como implementar essa ideia?

A ideia de simplesmente deixar o algoritmo rodar funciona, mas utilizaremos a ideia de vértices auxiliares para entender o porquê. Agora não queremos apenas chegar no vértice com o menor caminho possível, queremos chegar em um vértice com o k-ésimo menor caminho \forall 1 \le k \le K. Perceba que não precisamos passar pelo mesmo vértice mais de K vezes, pois os K menores caminhos até o vértice N utilizarão no máximo os K menores caminhos até esse vértice. Assim, um mesmo vértice vai "conter" K vértices auxiliares - os K menores caminhos até ele. Nesse novo grafo, basta rodarmos o algoritmo de Dijkstra a partir do vértice 1_0 (o vértice que representa o menor caminho até o vértice inicial) e imprimir a distância toda vez que passamos por um vértice N_i. Perceba que chegaremos nos vértices N_i em ordem crescente de distância, assim como foi pedido no enunciado.

Complexidade

O algoritmo é semelhante à um Dijkstra normal com N*K vértices, então a complexidade pode ser estimada em O(M \cdot K \cdot log(NK))

Recomendamos que você tente implementar o problema antes de ver o código. Veja a implementação nesse link.