Algoritmo que encontra o número de caminhos simples de a em

34

Alguém pode sugerir-me um algoritmo de tempo linear, que recebe como entrada um dirigido acíclico gráfico e dois vértices e e devolve o número de caminhos simples de a em . Eu tenho um algoritmo no qual executarei um DFS (Depth First Search), mas se o DFS encontrar , ele não mudará a cor (de branco para cinza) de qualquer um dos nós que no caminho para que se esse for o subcaminho de qualquer outro caminho, o DFS também o percorrerá novamente. Por exemplo, considere a lista de adjacências em que precisamos encontrar o número de caminhos de p a v .G=(V,E)ststG
tstpv

poszorsvsrryyvvwzwz
Aqui o DFS começará com p e digamos que vá para pz uma vez que não encontra v DFS será executado normalmente. caminho é psryv pois encontrar v que não irá alterar a cor dos vértices s,r,y,v para grey.Then o caminho pov desde cor de v é ainda white.Then o caminho posryv desde cor de s é branco e de forma semelhante caminho poryv.Também é mantido um contador que é incrementado quando v é encontrado.

Meu algoritmo está correto? caso contrário, quais modificações são necessárias para torná-lo correto ou quaisquer outras abordagens serão muito apreciadas.

Nota : Aqui eu considerei o algoritmo DFS que é fornecido no livro "Introdução aos algoritmos por Cormen", no qual ele colore os nós de acordo com seu status. Portanto, se o nó não for visitado, inexplorado e explorado, a cor será branca cinza e preto, respectivamente. Todas as outras coisas são padrão.

Saurabh
fonte
4
Observe que todos os caminhos em um gráfico acíclico direcionado são necessariamente simples (em virtude da aciclicidade).
Noldorin

Respostas:

37

Sua implementação atual calculará o número correto de caminhos em um DAG. No entanto, ao não marcar caminhos, levará um tempo exponencial. Por exemplo, na ilustração abaixo, cada estágio do DAG aumenta o número total de caminhos em um múltiplo de 3. Esse crescimento exponencial pode ser tratado com programação dinâmica.

dag

A computação do número de caminhos - em um DAG é dada pela recorrência, t Caminhos ( u ) = { 1 se  u = t ( u , v ) E Caminhos ( v ) caso contrário.st

Paths(u)={1if u=t(u,v)EPaths(v)otherwise.

Uma simples modificação do DFS calculará isso como

def dfs(u, t):
    if u == t:
        return 1
    else:
        if not u.npaths:
            # assume sum returns 0 if u has no children
            u.npaths = sum(dfs(c, t) for c in u.children)
        return u.npaths

Não é difícil ver que cada aresta é vista apenas uma vez, portanto, um tempo de execução de .O(V+E)

Nicholas Mancuso
fonte
Eu entendi o seu algoritmo e ele pode ser um pouco mais eficiente usando a programação dinâmica, já que as mesmas chamadas recursivas são chamadas muitas vezes, então é melhor economizar.
Saurabh
1
@SaurabhHota, está usando programação dinâmica. A primeira vez que o vértice é encontrado, ele calcula o número de caminhos que ele tem para . Isso é armazenado em u.npaths. Cada chamada subsequente para não recalculará seu número de caminhos, mas simplesmente retornará u.npaths. t uutu
Nicholas Mancuso
1
Para esses gráficos, a resposta não é apenas m ^ n onde m é o número de nós em uma coluna (3 aqui) en é o número de colunas excluindo s, t (4 aqui). a saída é 3 ^ 4 = 81 para o gráfico de exemplo.
Saadtaame
@saadtaame, com certeza; no entanto, minha intenção era apenas mostrar aumento exponencial à medida que o "comprimento" de um gráfico aumenta. Obviamente, para esse gráfico altamente estruturado, você pode contar em formato fechado, enquanto o algoritmo listado funciona para todos os gráficos.
Nicholas Mancuso
3
O tempo de execução pressupõe que você pode executar as adições necessárias em tempo constante, mas os números adicionados podem ter bits no pior caso. Se você deseja o número exato de caminhos, o tempo de execução (contando operações de bits) é realmente . Θ ( V ) O ( V E )O(V+E)Θ(V)O(VE)
18715 JeffE
15

Você só precisa observar que o número de caminhos de um nó para o nó de destino é a soma do número de caminhos de seus filhos para o destino. Você sabe que esse algoritmo sempre para porque seu gráfico não possui ciclos.

Agora, se você salvar o número de caminhos de um nó no destino ao visitar os nós, a complexidade do tempo se tornará linear no número de vértices e a memória linear no número de nós.

molyss
fonte
0

O número de caminhos entre dois vértices em um DAG pode ser encontrado usando a representação da matriz de adjacência.

Suponha que A é a matriz de adjacência de G. Tomando o poder K de A depois de adicionar a matriz de identidade, fornece o número de caminhos de comprimento <= K.

Como o comprimento máximo de qualquer caminho simples em um DAG é | V | -1, o cálculo de | V | -1ª potência forneceria o número de caminhos entre todos os pares de vértices.

O cálculo da | V | -1ª potência pode ser feito executando multiplicações de log (| V | -1) cada um dos TC: | V | ^ 2.

Vivek Anand Sampath
fonte
A pergunta pede um algoritmo de tempo linear. Seu algoritmo é mais lento que isso.
DW
@Vivek, você pode mencionar uma referência para os teoremas na sua resposta?
Hamideh