Visualizador de algoritmos de busca de caminho

veja diferentes algoritmos de busca competirem na mesma grade, fronteira por fronteira

A carregar a simulação interativa...

Lição

A teoria — Visualizador de algoritmos de busca de caminho

Três dos quatro algoritmos no menu suspenso são o mesmo algoritmo. Todos eles ordenam as células que aguardam para serem exploradas com uma única expressão, f(n) = g(n) + h(n) — custo até agora mais custo estimado restante — e diferem apenas em qual dos dois termos mantêm. Descarte h e você tem o Dijkstra. Ignore g e você tem o Greedy Best-First. O quarto, a busca em largura, é aquilo em que o Dijkstra se reduz quando todos os passos custam o mesmo.

O que significa cada símbolo

g(n)
o custo da rota mais barata encontrada até agora do início até a célula n. Um passo lateral ou vertical custa 1; uma diagonal custa √2, porque o passo é medido como um comprimento em vez de ser contado como um único movimento.
h(n)
a estimativa do custo que ainda está por vir. Para o Dijkstra e a busca em largura, ela não é meramente não utilizada — ela é zero, e é precisamente isso que os torna a mesma expressão com um termo faltando.
f(n)
a chave de ordenação: a célula com o menor f é a próxima a ser explorada. Ela é exibida acima da grade com os próprios números da célula atual substituídos, para que a escolha que o algoritmo acabou de fazer seja visível em vez de apenas declarada.
frontier
as células âmbar — descobertas, mas ainda não exploradas. Nós expandidos conta o que saiu deste conjunto, tornando-o uma medida do trabalho realizado, e não da qualidade da resposta.

De onde vem a fórmula

  1. Defina o que "mais curto" significa antes de escolher um algoritmo. O custo de um caminho é a soma dos comprimentos de seus passos: 1 para um movimento lateral ou vertical, √2 para uma diagonal. As células não são contadas; as distâncias são somadas.
  2. Agora o laço, que é idêntico para todos os quatro: retire uma célula da fronteira, marque-a como explorada e ofereça cada vizinho passável de volta à fronteira com um g atualizado. Observe o que este laço nunca menciona — uma heurística, a direção do objetivo ou qual algoritmo você escolheu.
  3. Assim, a única decisão que resta é qual célula retirar, e trata-se de uma única expressão. Ordene por g + h e você tem o A*. Defina h = 0 e a ordenação é feita apenas pelo custo até agora — esse é o Dijkstra, expandindo-se para fora em anéis porque não tem ideia de onde está o objetivo. Em vez disso, ignore g e a ordenação é feita apenas pela estimativa — o Greedy Best-First, correndo em direção ao objetivo e aceitando qualquer rota pela qual tenha chegado.
  4. A busca em largura não ordena de forma alguma: primeiro a entrar, primeiro a sair. Com Permitir diagonais desativado, cada passo custa exatamente 1, portanto a ordem em que as células chegam é a ordem de aumento de g — e a busca em largura, portanto, explora precisamente o mesmo que o Dijkstra explora. Você pode confirmar isso sem gerar a grade novamente: alterne entre os dois e Nós expandidos não se move. Ative as diagonais e o argumento morre com isso, porque uma diagonal custa √2 em vez de 1 e a ordem de chegada deixa de acompanhar o custo.

Como ler o que vê

A pontuação de prioridade fica acima da grade com os próprios g e h da célula atual preenchidos, para que você possa ler a ordenação que produziu a última escolha. Abaixo dela estão duas contagens: Nós expandidos e Comprimento do caminho. Âmbar é a fronteira, índigo é o já explorado. Alterar o algoritmo não gera uma nova grade, e é isso que faz a comparação valer a pena — na mesma disposição para os quatro algoritmos, os Nós expandidos do Dijkstra nunca são menores que os do A*, e os do Greedy Best-First são uma pequena fração de qualquer um deles.

Pressupõe
Custos de passo que nunca são negativos e uma grade que não muda enquanto a busca é executada. O início é sempre a célula superior esquerda e o objetivo é a inferior direita. O fechamento de uma célula é definitivo — o laço nunca reavalia uma célula — e isso só é seguro porque nenhuma rota posterior pode chegar com menor custo quando cada passo adiciona uma quantidade não negativa.
Falha quando
Nós expandidos é o número que muda mais drasticamente e não é uma medida de qualidade. Escolha o Greedy Best-First: na mesma grade ele explora uma pequena fração do que o A* explora e, na maioria dos layouts, retorna um Comprimento do caminho mais longo. Gere algumas grades novas e observe as duas contagens se moverem em direções opostas. Examinar menos células é uma afirmação sobre o quão duro o algoritmo trabalhou, nunca sobre quão boa foi sua resposta.

por que as heurísticas importam 🖖

A fórmula f(n)=g(n)+h(n) faz o A* preferir nós que são baratos até agora e ainda parecem próximos do objetivo. Se h nunca superestima o custo restante, o A* mantém sua garantia de caminho mais curto; um h admissível mais forte explora menos células desnecessárias. Alterne o menu suspenso de algoritmo para ver o que acontece ao remover a heurística (Dijkstra), o custo até agora (Greedy) ou toda a pontuação (BFS).

Um laço, quatro personalidades 🖖

Os quatro algoritmos executam exatamente o mesmo ciclo: retiram de uma lista de espera a célula mais promissora (a fronteira, a âmbar), marcam-na como visitada (a índigo) e acrescentam à lista as células vizinhas desimpedidas. Diferem apenas no critério usado para escolher a célula mais promissora. O número de nós expandidos funciona como medida de desempenho, mas não varia como seria de esperar. Numa grelha vazia, o A* expande todas as células, pois, com a distância de Manhattan, todos os percursos monótonos até ao canto têm o mesmo valor de f e nenhum se destaca. Quando se acrescentam obstáculos, o número diminui.

As diagonais podem quebrar a garantia 🖖

Ative 'Permitir diagonal' junto com a heurística de Manhattan e o A* pode devolver silenciosamente um caminho que não é o mais curto. Aqui um passo diagonal custa apenas √2 ≈ 1.41, mas a distância de Manhattan o cobra como 2 — então a heurística superestima, torna-se inadmissível e a garantia de otimalidade se perde. Mude para Euclidiana, que nunca ultrapassa a distância em linha reta, e o caminho mais curto retorna.

Percurso de aprendizagem

Contar trabalho, não segundos

Referências (3)

Problemas de exemplo

  • grade aberta - Numa grelha de 20 × 20 com um décimo das células bloqueado, o A* continua a expandir a maior parte da grelha: todos os percursos monótonos têm f = 38, pelo que o empate persiste.
  • tipo labirinto - Os obstáculos tornam o A* mais rápido. Uma densidade de bloqueio de 0,28 desfaz os empates que encarecem a pesquisa numa grelha aberta, e o algoritmo acaba por percorrer cerca de metade das células livres.
  • heurística fraca - Numa grelha aberta com ligações em 4 direções, a distância de Manhattan é exata, enquanto a euclidiana fica sempre aquém; por isso, esta é a mais fraca das duas heurísticas admissíveis. O caminho é o mesmo, mas são percorridas cerca de um terço de células a mais.
  • dijkstra explora - A mesma grelha de 24 × 24, com a densidade de 0,22 usada em Heurística fraca, mas agora sem qualquer heurística. Sem informação sobre o objetivo, Dijkstra expande mais cerca de metade das células do que o A*.
  • armadilha greedy - A busca gulosa avalia apenas h, avançando diretamente para o objetivo e expandindo menos de metade das células percorridas pelo A*. Na maioria dos casos, porém, encontra um caminho mais longo. É essa a contrapartida.
  • bfs + diagonais - A BFS não dispõe de informação sobre o objetivo, pelo que alcança quase todas as células abertas. Quando são permitidas diagonais, cada movimento diagonal conta como um passo; assim, minimiza o número de passos, não a distância.