Estou tentando encontrar uma solução eficiente para o meu problema. Vamos supor que eu tenha um gráfico ponderado positivo G
contendo 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?
fonte
Respostas:
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 j no 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.
fonte
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
fonte