Caminho mais curto que passa por nós específicos

8

Estou tentando encontrar uma solução eficiente para o meu problema. Vamos supor que eu tenha um gráfico ponderado positivo Gcontendo 100 nós (cada nó esteja numerado) e seja um gráfico acíclico. Portanto, não pode haver borda como 2,2 ou 2,1. Eu tenho uma lista de nós, digamos 10 do gráfico G. Digamos que cada um desses nós também esteja em uma matriz. Estou procurando uma maneira de encontrar o peso total do caminho mais curto do nó 1 ao 100 que passa por pelo menos algum detalhe (digamos 5) desses nós dessa lista.

Para simplificá-lo, considere o gráfico com 6 nós, 0 ... 5, agora os nós 1 e 4 estão marcados como pontos pelos quais poderíamos especificar a passagem. Digamos que os caminhos existentes sejam 0-1-2-5, 0-3-4-5 e 1-4. Agora, digamos que todas as arestas são ponderadas como 5, exceto que 3 a 4 são ponderadas como 1. Se executarmos um algoritmo de caminho mais curto, ele basicamente encontrará o caminho 0-3-4-5, pois é ponderado 11. No entanto, se executarmos um algoritmo especificando a quantidade mínima de pontos especificados e tente a quantidade 2. Em seguida, o algoritmo deve estar executando em 0-1-4-5, que é ponderado como 15.

Eu escrevi assim

    shortestPath(destinationNode, minAmount) 

        if(destinationNode == srcNode && minAmount < 1) 
            return 0

        else if(destinationNode == srcNode && minAmount > 1) 
            return INFINITY

        int destNo = destinationNode get number
        int cost = INFINITY
        for (int i = 0; i < destNo; i++)
            if (d[i][destNo] != null) 
                int minimumAmountCount = minAmount;
                for (int j = 0; j < marked.length(); j++) 
                    if (marked[j] == i) 
                        minimumAmountCount = minimumAmountCount - 1;

                cost = MIN(cost, shortestPath(Node(i), minimumAmountCount);

        return cost;

Basicamente, chamamos esse algoritmo usando o nó de destino e a quantidade mínima de nós dessa lista. Primeiramente, queremos ter certeza de que essa é uma função recursiva e que deve ter um ponto de parada, que seria quando o destino passado for igual ao nó de origem (que é essencialmente o nó # 0). O segundo caso que precisamos verificar é se visitamos uma quantidade suficiente; portanto, se for menor que 1 (0 ou número negativo), visitamos pontos suficientes e retornamos 0, pois a distância do nó # 0 ao nó # 0 seria 0. Se como não visitamos uma quantidade suficiente, retornamos o infinito para que o algoritmo considere outros caminhos.

Portanto, para que a peça retornada funcione, precisamos definir o número do nó de destino (se considerarmos que temos 100 nós, seria o nó nº 99 no início inicial) e inicializar o custo como infinito.

Em seguida, executamos um loop for que começa de 0 (essencialmente o nó # 0) até o número do nó atual, isso ocorre porque não existem arestas no gráfico. Usando o número do nó, verificamos a partir da matriz se existe um peso existente para esses nós. Se existir, inicializamos uma variável para a quantidade mínima atual e, em seguida, executamos um loop e verificamos se a origem do destino atual está na lista de nós marcados. Se estiver marcado, simplesmente decrementamos o valor mínimo.

Para a etapa final, executamos a função novamente, alterando o destino como a fonte atual e com o valor mínimo atual.

Mas parece muito caro, considerando o fato de que a pior complexidade do loop aninhado leva O (| Node | ^ 2) e a recorrência total levaria O (| Node | ^ 2 * | Edges |). Existe alguma outra solução eficiente para esse problema?

Sarp Kaya
fonte
Você pode explicar seu algoritmo em palavras?
Yuval Filmus 10/10
@YuvalFilmus Eu fiz isso agora.
precisa

Respostas:

2

Calcule o caminho mais curto entre todos os pares dos doze nós especiais (nós 1, 100 e todos os dez de seus nós específicos) e use-os como comprimentos de arestas em um novo gráfico que consiste apenas desses doze nós. Agora, você tem um gráfico contendo doze nós e deseja encontrar o caminho mais curto de 1 a 100 que usa pelo menos cinco outros nós. Agora, você pode usar seu algoritmo (que eu acho que é apenas programação dinâmica) neste gráfico, que é muito menor. A solução no novo gráfico fornecerá uma solução para o gráfico original, que você pode encontrar substituindo as arestas na solução no novo gráfico pelos caminhos mais curtos que você calculou na primeira etapa.

Para o seu exemplo, teremos 4 nós no novo gráfico. Os comprimentos das arestas no novo gráfico são: 0-1: 5, 0-4: 6, 0-5: 11, 1-4: 5, 1-5: 10, 4-5: 5. Eles correspondem aos caminhos mais curtos entre os nósEu e jno gráfico original. O caminho mais curto, incluindo um nó da lista, é 0-4-5, que possui comprimento 11. Agora, substituir cada aresta nesse caminho pelo caminho calculado na primeira etapa fornece o caminho 0-3-4-5 no original gráfico.

Peter Shor
fonte
Não, pelo menos, outros cinco nós. Assuma issoN são todos os nós euN onde L é a lista de nós e |P|<=|eu|onde | P | é a quantidade de pontos mínimos em que o gráfico deve ser construído. O conteúdo de P é obtido de L, pois utiliza a quantidade mínima (| P |) de elementos L. Portanto, há pelo menos cinco nós nessa lista de 10
Sarp Kaya 10/10
Adicionei um exemplo na minha pergunta. Por favor, verifique isso?
quer
Mas no novo gráfico, além dos nós inicial e final, existem apenas esses dez nós.
quer
11
Estou dizendo, comece com o gráfico original e construa um novo gráfico. Resolva um problema modificado no novo gráfico e transfira a solução de volta para o gráfico original. O novo gráfico contém apenas 12 nós. As distâncias no novo gráfico correspondem aos caminhos mais curtos entre esses nós selecionados no gráfico original.
quer
2
Eu não estou indo. Se alguém quiser pegar minha solução e escrever outra resposta explicando em pseudocódigo, deve se sentir à vontade para seguir em frente.
Peter Shor
0

Se tudo o que você tem são 100 nós e seus arcos são dados ou fáceis de calcular: não se preocupe.

Caso contrário: seu gráfico provavelmente é muito escasso (muito mais pares de nós com arcos do que sem arcos). Portanto, use listas vinculadas ou alguma outra estrutura de dados que permita iterar apenas sobre arcos, sem ter que pular os não-arcos. Os nomes dessas estruturas de dados dependem do idioma; vários tipos de qualidade de listas ou dicionários Java ou C #, como, por exemplo, hashes em Perl ou matrizes associativas em PHP.

Eu os usaria para criar um mapeamento de nós para encaminhar arcos (ou seja, pares de custo e nó de destino) e outro de nós para arcos anteriores.

Eu alocaria mais duas para manter as distâncias nó a nó de cada nó para cada nó intermediário e de cada nó intermediário para cada nó, e as calcularia usando o algoritmo padrão (Floyd's, também conhecido como Dijkstra's, ou, erroneamente) De Warshall).

Eu alocaria mais uma para manter as distâncias finais nó a nó e as calcularia como

d(x,y)=mEunzEu(d(x,z)+d(z,y))
para os nós intermediários Eu.
reinierpost
fonte
Não tenho 100 nós, só queria dar um número de exemplo. Você poderia explicar suas frases usando os idiomas pseudocódigo ou java / C ++?
precisa
Eu sou muito preguiçoso. Desculpa.
Reinierpost 10/10