Qual é a diferença entre retrocesso e primeira pesquisa em profundidade?
Backtracking é um algoritmo de propósito mais geral.
A pesquisa em profundidade é uma forma específica de retrocesso relacionada à pesquisa de estruturas de árvore. Da Wikipedia:
Um começa na raiz (selecionando algum nó como a raiz no caso do gráfico) e explora o máximo possível ao longo de cada ramificação antes de retroceder.
Ele usa o retrocesso como parte de seu meio de trabalhar com uma árvore, mas está limitado a uma estrutura de árvore.
O retrocesso, entretanto, pode ser usado em qualquer tipo de estrutura onde partes do domínio podem ser eliminadas - seja ou não uma árvore lógica. O exemplo do Wiki usa um tabuleiro de xadrez e um problema específico - você pode olhar para um movimento específico e eliminá-lo, depois voltar para o próximo movimento possível, eliminá-lo etc.
Acho que essa resposta a outra pergunta relacionada oferece mais insights.
Para mim, a diferença entre o retrocesso e o DFS é que o retrocesso lida com uma árvore implícita e o DFS com uma explícita. Isso parece trivial, mas significa muito. Quando o espaço de busca de um problema é visitado por retrocesso, a árvore implícita é percorrida e podada no meio dele. Ainda assim, para o DFS, a árvore / gráfico com que ele lida é explicitamente construída e casos inaceitáveis já foram descartados, ou seja, podados, antes que qualquer pesquisa seja feita.
Portanto, retroceder é DFS para árvore implícita, enquanto DFS retrocede sem podar.
fonte
O retrocesso é geralmente implementado como DFS mais remoção de pesquisa. Você atravessa a árvore do espaço de busca, primeiro construindo soluções parciais ao longo do caminho. O DFS de força bruta pode construir todos os resultados da pesquisa, mesmo os que não fazem sentido na prática. Isso também pode ser muito ineficiente para construir todas as soluções (n! Ou 2 ^ n). Portanto, na realidade, ao fazer o DFS, você também precisa remover as soluções parciais, que não fazem sentido no contexto da tarefa real, e se concentrar nas soluções parciais, que podem levar a soluções ótimas válidas. Esta é a técnica real de retrocesso - você descarta as soluções parciais o mais cedo possível, dá um passo para trás e tenta encontrar o ótimo local novamente.
Nada para de percorrer a árvore do espaço de pesquisa usando BFS e executar a estratégia de retrocesso ao longo do caminho, mas não faz sentido na prática porque você precisaria armazenar o estado de pesquisa camada por camada na fila, e a largura da árvore cresce exponencialmente até a altura, portanto, perderíamos muito espaço muito rapidamente. É por isso que as árvores geralmente são percorridas usando DFS. Neste caso, o estado de pesquisa é armazenado na pilha (pilha de chamadas ou estrutura explícita) e não pode exceder a altura da árvore.
fonte
Normalmente, uma pesquisa em profundidade é uma forma de iterar por meio de uma estrutura de gráfico / árvore real em busca de um valor, enquanto o retrocesso é iterar por um espaço de problema em busca de uma solução. Backtracking é um algoritmo mais geral que não necessariamente se relaciona com árvores.
fonte
Eu diria que o DFS é a forma especial de retrocesso; retrocesso é a forma geral de DFS.
Se estendermos o DFS a problemas gerais, podemos chamá-lo de retrocesso. Se usarmos o retrocesso para problemas relacionados à árvore / gráfico, podemos chamá-lo de DFS.
Eles carregam a mesma ideia no aspecto algorítmico.
fonte
De acordo com Donald Knuth, é a mesma coisa. Aqui está o link em seu artigo sobre o algoritmo Dancing Links, que é usado para resolver problemas "não-árvore", como N-rainhas e o solucionador Sudoku.
fonte
IMHO, a maioria das respostas são imprecisas e / ou sem qualquer referência a verificar. Então, deixe-me compartilhar uma explicação muito clara com uma referência .
Primeiro, o DFS é um algoritmo geral de passagem (e pesquisa) de gráfico. Portanto, pode ser aplicado a qualquer gráfico (ou mesmo floresta). Árvore é um tipo especial de gráfico, portanto, o DFS também funciona para árvore. Em essência, vamos parar de dizer que funciona apenas para uma árvore ou semelhantes.
Baseado em [1], Backtracking é um tipo especial de DFS usado principalmente para economizar espaço (memória). A distinção que estou prestes a mencionar pode parecer confusa, pois nos algoritmos de Graph desse tipo estamos tão acostumados a ter representações de lista de adjacências e usar um padrão iterativo para visitar todos os vizinhos imediatos ( para árvore, são os filhos imediatos ) de um nó , muitas vezes ignoramos que uma má implementação de get_all_immediate_neighbors pode causar uma diferença no uso de memória do algoritmo subjacente.
Além disso, se um nó de grafo tem fator de ramificação b e diâmetro h ( para uma árvore, esta é a altura da árvore ), se armazenarmos todos os vizinhos imediatos em cada etapa da visita a um nó, os requisitos de memória serão big-O (bh) . No entanto, se pegarmos apenas um único vizinho (imediato) de cada vez e o expandirmos, a complexidade da memória se reduzirá a big-O (h) . Enquanto o primeiro tipo de implementação é denominado DFS , o último tipo é denominado Backtracking .
Agora você vê, se você está trabalhando com linguagens de alto nível, provavelmente você está realmente usando o Backtracking disfarçado de DFS. Além disso, manter o controle dos nós visitados para um conjunto de problemas muito grande pode consumir muita memória; pedindo um design cuidadoso de get_all_immediate_neighbors (ou algoritmos que podem lidar com a revisitação de um nó sem entrar em um loop infinito).
[1] Stuart Russell e Peter Norvig, Artificial Intelligence: A Modern Approach, 3rd Ed
fonte
A profundidade primeiro é um algoritmo para percorrer ou pesquisar uma árvore. Vejo aqui . Backtracking é um termo muito mais amplo que é usado sempre que um candidato a solução é formado e posteriormente descartado pelo retrocesso para um estado anterior. Veja aqui . A primeira pesquisa em profundidade usa backtracking para pesquisar primeiro um branch (candidato à solução) e, se não for bem-sucedido, pesquisar os outros branch (s).
fonte
O DFS descreve a maneira como você deseja explorar ou percorrer um gráfico. Concentra-se no conceito de ir o mais fundo possível, dada a escolha.
O retrocesso, embora geralmente implementado via DFS, concentra-se mais no conceito de remoção de subespaços de pesquisa pouco promissores o mais cedo possível.
fonte
Em uma pesquisa aprofundada , você começa na raiz da árvore e, em seguida, explora ao longo de cada galho, depois volta para cada nó pai subsequente e atravessa seus filhos
Backtracking é um termo generalizado para começar no final de uma meta e retroceder gradativamente, construindo gradualmente uma solução.
fonte
IMO, em qualquer nó específico do retrocesso, você tenta aprofundar primeiro a ramificação em cada um de seus filhos, mas antes de se ramificar em qualquer nó filho, você precisa "apagar" o estado anterior do filho (esta etapa é equivalente a voltar caminhar até o nó pai). Em outras palavras, cada estado de irmão não deve impactar um ao outro.
Ao contrário, durante o algoritmo DFS normal, você geralmente não tem essa restrição, você não precisa apagar (retroceder) o estado anterior dos irmãos para construir o próximo nó irmão.
fonte
Ideia - Comece de qualquer ponto, verifique se é o ponto final desejado, se sim, então encontramos uma solução senão vai para todas as próximas posições possíveis e se não pudermos ir mais longe, volte para a posição anterior e procure outras alternativas marcando essa corrente o caminho não nos levará à solução.
Agora backtracking e DFS são 2 nomes diferentes dados à mesma ideia aplicada em 2 tipos de dados abstratos diferentes.
Se a ideia é aplicada na estrutura de dados da matriz, chamamos isso de backtracking.
Se a mesma ideia for aplicada em árvore ou gráfico, então o chamamos de DFS.
O clichê aqui é que uma matriz pode ser convertida em um gráfico e um gráfico pode ser transformado em uma matriz. Então, nós realmente aplicamos a ideia. Se estiver em um gráfico, então o chamamos de DFS e se estiver em uma matriz, então o chamamos de retrocesso.
A ideia em ambos os algoritmos é a mesma.
fonte
O retrocesso é apenas uma primeira pesquisa em profundidade com condições de encerramento específicas.
Considere caminhar por um labirinto onde para cada etapa que você toma uma decisão, essa decisão é uma chamada para a pilha de chamadas (que conduz sua primeira pesquisa em profundidade) ... se você chegar ao fim, poderá retornar ao seu caminho. No entanto, se você chegar a um beco sem saída, deseja retornar de uma determinada decisão, basicamente retornando de uma função em sua pilha de chamadas.
Então, quando penso em retroceder, me preocupo
Eu explico no meu vídeo sobre retrocesso aqui .
Uma análise do código de backtracking está abaixo. Neste código de retrocesso, quero todas as combinações que resultarão em uma determinada soma ou meta. Portanto, eu tenho 3 decisões que fazem chamadas para minha pilha de chamadas, em cada decisão eu posso escolher um número como parte do meu caminho para chegar ao número de destino, pular esse número ou selecioná-lo e selecioná-lo novamente. E então, se eu atingir uma condição de encerramento, minha etapa de retrocesso é apenas retornar . Retornar é a etapa de retrocesso, porque sai dessa chamada na pilha de chamadas.
fonte