Pregunta

Decir que tengo los nodos conectados en la continuación de la moda, ¿cómo puedo llegar al número de rutas que existen entre los puntos dados, y la ruta de los detalles?

1,2 //node 1 and 2 are connected
2,3
2,5
4,2
5,11
11,12
6,7
5,6
3,6
6,8
8,10
8,9

Encontrar las rutas del 1 al 7:

Respuesta:2 rutas de encontrar y son

1,2,3,6,7
1,2,5,6,7

alt text

implementación que se encuentran aquí es bueno me voy a utilizar el mismo

Aquí está el fragmento de código desde el enlace de arriba en python

# a sample graph
graph = {'A': ['B', 'C','E'],
             'B': ['A','C', 'D'],
             'C': ['D'],
             'D': ['C'],
             'E': ['F','D'],
             'F': ['C']}

class MyQUEUE: # just an implementation of a queue

    def __init__(self):
        self.holder = []

    def enqueue(self,val):
        self.holder.append(val)

    def dequeue(self):
        val = None
        try:
            val = self.holder[0]
            if len(self.holder) == 1:
                self.holder = []
            else:
                self.holder = self.holder[1:]   
        except:
            pass

        return val  

    def IsEmpty(self):
        result = False
        if len(self.holder) == 0:
            result = True
        return result


path_queue = MyQUEUE() # now we make a queue


def BFS(graph,start,end,q):

    temp_path = [start]

    q.enqueue(temp_path)

    while q.IsEmpty() == False:
        tmp_path = q.dequeue()
        last_node = tmp_path[len(tmp_path)-1]
        print tmp_path
        if last_node == end:
            print "VALID_PATH : ",tmp_path
        for link_node in graph[last_node]:
            if link_node not in tmp_path:
                #new_path = []
                new_path = tmp_path + [link_node]
                q.enqueue(new_path)

BFS(graph,"A","D",path_queue)

-------------results-------------------
['A']
['A', 'B']
['A', 'C']
['A', 'E']
['A', 'B', 'C']
['A', 'B', 'D']
VALID_PATH :  ['A', 'B', 'D']
['A', 'C', 'D']
VALID_PATH :  ['A', 'C', 'D']
['A', 'E', 'F']
['A', 'E', 'D']
VALID_PATH :  ['A', 'E', 'D']
['A', 'B', 'C', 'D']
VALID_PATH :  ['A', 'B', 'C', 'D']
['A', 'E', 'F', 'C']
['A', 'E', 'F', 'C', 'D']
VALID_PATH :  ['A', 'E', 'F', 'C', 'D']
¿Fue útil?

Solución

primero en amplitud de búsqueda atraviesa un gráfico y, de hecho, encuentra todos los caminos de una partida nodo. Por lo general, BFS no conserva todos los caminos, sin embargo. En su lugar, se actualiza una función π prededecessor para guardar el camino más corto. Usted puede modificar fácilmente el algoritmo de manera que no lo hace π(n) única tienda un predecesor, pero una lista de posibles predecesores.

A continuación, todos los caminos posibles están codificados en esta función, y por la que atraviesa π recursiva obtener todas las combinaciones posibles de ruta.

Una buena pseudocódigo que utiliza esta notación se puede encontrar en Introducción a los algoritmos por Cormen et al. y, posteriormente, se ha utilizado en muchos guiones Universitarios sobre el tema. Una búsqueda en Google de “BFS pseudocódigo predecesor π” arranca este golpe en la pila de cambio .

Otros consejos

Para los que no son expertos Python, el mismo código en C ++

//@Author :Ritesh Kumar Gupta
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
vector<vector<int> >GRAPH(100);
inline void print_path(vector<int>path)
{
    cout<<"[ ";
    for(int i=0;i<path.size();++i)
    {
        cout<<path[i]<<" ";
    }
    cout<<"]"<<endl;
}
bool isadjacency_node_not_present_in_current_path(int node,vector<int>path)
{
    for(int i=0;i<path.size();++i)
    {
        if(path[i]==node)
        return false;
    }
    return true;
}
int findpaths(int source ,int target ,int totalnode,int totaledge )
{
    vector<int>path;
    path.push_back(source);
    queue<vector<int> >q;
    q.push(path);

    while(!q.empty())
    {
        path=q.front();
        q.pop();

        int last_nodeof_path=path[path.size()-1];
        if(last_nodeof_path==target)
        {
            cout<<"The Required path is:: ";
            print_path(path);
        }
        else
        {
            print_path(path);
        }

        for(int i=0;i<GRAPH[last_nodeof_path].size();++i)
        {
            if(isadjacency_node_not_present_in_current_path(GRAPH[last_nodeof_path][i],path))
            {

                vector<int>new_path(path.begin(),path.end());
                new_path.push_back(GRAPH[last_nodeof_path][i]);
                q.push(new_path);
            }
        }




    }
    return 1;
}
int main()
{
    //freopen("out.txt","w",stdout);
    int T,N,M,u,v,source,target;
    scanf("%d",&T);
    while(T--)
    {
        printf("Enter Total Nodes & Total Edges\n");
        scanf("%d%d",&N,&M);
        for(int i=1;i<=M;++i)
        {
            scanf("%d%d",&u,&v);
            GRAPH[u].push_back(v);
        }
        printf("(Source, target)\n");
        scanf("%d%d",&source,&target);
        findpaths(source,target,N,M);
    }
    //system("pause");
    return 0;
}

/*
Input::
1
6 11
1 2 
1 3
1 5
2 1
2 3
2 4
3 4
4 3
5 6
5 4
6 3
1 4

output:
[ 1 ]
[ 1 2 ]
[ 1 3 ]
[ 1 5 ]
[ 1 2 3 ]
The Required path is:: [ 1 2 4 ]
The Required path is:: [ 1 3 4 ]
[ 1 5 6 ]
The Required path is:: [ 1 5 4 ]
The Required path is:: [ 1 2 3 4 ]
[ 1 2 4 3 ]
[ 1 5 6 3 ]
[ 1 5 4 3 ]
The Required path is:: [ 1 5 6 3 4 ]


*/

El algoritmo de Dijkstra se aplica más a caminos ponderados y parece que el cartel fue querer encontrar todos los caminos, no sólo el más corto.

Para esta aplicación, construiría un gráfico (suena su aplicación como si no tendría que ser dirigida) y utilizar su método de búsqueda favorito. Parece que usted desea que todos los caminos, no sólo una conjetura en el más corto, por lo que utiliza un simple algoritmo recursivo de su elección.

El único problema con esto es que si el gráfico puede ser cíclico.

Con las conexiones:

  • 1, 2
  • 1, 3
  • 2, 3
  • 2, 4

En la búsqueda de un camino a partir de 1-> 4, usted podría tener un ciclo de 1 -> 2 -> 3 -.> 1

En ese caso, entonces me gustaría mantener una pila que lo atraviesa los nodos. Aquí hay una lista con los pasos para que el gráfico y la pila resultante (lo siento por el formato - no hay opción de tabla):

nodo actual (posibles próximos nodos menos de dónde venimos) [pila]

  1. 1 (2, 3) [1]
  2. 2 (3, 4) [1, 2]
  3. 3 (1) [1, 2, 3]
  4. 1 (2, 3) [1, 2, 3, 1] // error - duplicar el número en la pila - detectó ciclo
  5. 3 () [1, 2, 3] // volver-escalonado al nodo tres y reventado 1 de la pila. No hay más nodos para explorar desde aquí
  6. 2 (4) [1, 2] // volver-caminado al nodo 2 y se metió 1 de la pila.
  7. 4 () [1, 2, 4] // nodo de destino encontrado - pila récord para un camino. No hay más nodos para explorar desde aquí
  8. 2 () [1, 2] // volver-escalonado al nodo 2 y aparecido 4 de la pila. No hay más nodos para explorar desde aquí
  9. 1 (3) [1] // volver-escalonado para el nodo 1 y hecho estallar 2 de la pila.
  10. 3 (2) [1, 3]
  11. 2 (1, 4) [1, 3, 2]
  12. 1 (2, 3) [1, 3, 2, 1] // error - duplicar el número en la pila - detectó ciclo
  13. 2 (4) [1, 3, 2] // volver-escalonado al nodo 2 y hecho estallar 1 de la pila
  14. 4 () [1, 3, 2, 4] nodo de destino encontrado - pila récord para un camino. No hay más nodos para explorar desde aquí
  15. 2 () [1, 3, 2] // volver-escalonado al nodo 2 y aparecido 4 de la pila. No más nodos
  16. 3 () [1, 3] // volver-escalonado al nodo 3 y hecho estallar 2 de la pila. No más nodos
  17. 1 () [1] // volver-escalonado para el nodo 1 y aparecido 3 de la pila. No más nodos
  18. Hecho con 2 caminos registrados de [1, 2, 4] y [1, 3, 2, 4]

El código original es un poco complicado y es posible que desee utilizar el collections.deque su lugar si desea utilizar BFS de encontrar si existe un camino entre 2 puntos en la gráfica. Aquí es una solución rápida Pirateé arriba:

Nota: este método podría continuar infinitamente si no existe una ruta entre los dos nodos. No he probado todos los casos, tu caso es distinto.

from collections import deque

# a sample graph
  graph = {'A': ['B', 'C','E'],
           'B': ['A','C', 'D'],
           'C': ['D'],
           'D': ['C'],
           'E': ['F','D'],
           'F': ['C']}

   def BFS(start, end):
    """ Method to determine if a pair of vertices are connected using BFS

    Args:
      start, end: vertices for the traversal.

    Returns:
      [start, v1, v2, ... end]
    """
    path = []
    q = deque()
    q.append(start)
    while len(q):
      tmp_vertex = q.popleft()
      if tmp_vertex not in path:
        path.append(tmp_vertex)

      if tmp_vertex == end:
        return path

      for vertex in graph[tmp_vertex]:
        if vertex not in path:
          q.append(vertex)

En Prolog (específicamente, SWI-Prolog)

:- use_module(library(tabling)).

% path(+Graph,?Source,?Target,?Path)
:- table path/4.

path(_,N,N,[N]).
path(G,S,T,[S|Path]) :-
    dif(S,T),
    member(S-I, G), % directed graph
    path(G,I,T,Path).

prueba:

paths :- Graph =
    [ 1- 2  % node 1 and 2 are connected
    , 2- 3 
    , 2- 5 
    , 4- 2 
    , 5-11
    ,11-12
    , 6- 7 
    , 5- 6 
    , 3- 6 
    , 6- 8 
    , 8-10
    , 8- 9
    ],
    findall(Path, path(Graph,1,7,Path), Paths),
    maplist(writeln, Paths).

?- paths.
[1,2,3,6,7]
[1,2,5,6,7]
true.

Si desea que todos los caminos, el uso de la recursividad.

Uso de una lista de adyacencia, preferiblemente, crear una función f () que intenta llenar en una lista actual de vértices visitados. De esta manera:

void allPaths(vector<int> previous, int current, int destination)
{
    previous.push_back(current);

    if (current == destination)
        //output all elements of previous, and return

    for (int i = 0; i < neighbors[current].size(); i++)
        allPaths(previous, neighbors[current][i], destination);
}

int main()
{
    //...input
    allPaths(vector<int>(), start, end);
}

Debido al hecho de que el vector se pasa por valor (y por tanto los cambios realizados más abajo en el procedimiento recursivo no son permanentes), todas las combinaciones posibles se enumeran.

Puede ganar un poco de eficiencia pasando el anterior vector de referencia (y así no tener que copiar el vector una y otra vez), sino que tendrá que asegurarse de que las cosas se ponen popped_back () manualmente.

Una cosa más: si el gráfico tiene ciclos, esto no va a funcionar. (Supongo que en este caso usted quiere encontrar todos los simples caminos, a continuación) Antes de añadir algo en el anterior vector, primer cheque si ya está ahí.

Si desea que todos los más cortos caminos, utilice la sugerencia de Konrad con este algoritmo.

dada la matriz de adyacencia:

{0, 1, 3, 4, 0, 0}

{0, 0, 2, 1, 2, 0}

{0, 1, 0, 3, 0, 0}

{0, 1, 1, 0, 0, 1}

{0, 0, 0, 0, 0, 6}

{0, 1, 0, 1, 0, 0}

el siguiente Wolfram Mathematica código de resolver el problema de encontrar todos los simples caminos entre dos nodos de un grafo.He utilizado simple repetición, y dos mundiales de var para mantener un seguimiento de los ciclos y almacenar el resultado deseado.el código no ha sido optimizado solo para el bien de la claridad del código.la "impresión" debería ser útil para aclarar cómo funciona.

cycleQ[l_]:=If[Length[DeleteDuplicates[l]] == Length[l], False, True];
getNode[matrix_, node_]:=Complement[Range[Length[matrix]],Flatten[Position[matrix[[node]], 0]]];

builtTree[node_, matrix_]:=Block[{nodes, posAndNodes, root, pos},
    If[{node} != {} && node != endNode ,
        root = node;
        nodes = getNode[matrix, node];
        (*Print["root:",root,"---nodes:",nodes];*)

        AppendTo[lcycle, Flatten[{root, nodes}]];
        If[cycleQ[lcycle] == True,
            lcycle = Most[lcycle]; appendToTree[root, nodes];,
            Print["paths: ", tree, "\n", "root:", root, "---nodes:",nodes];
            appendToTree[root, nodes];

        ];
    ];

appendToTree[root_, nodes_] := Block[{pos, toAdd},
    pos = Flatten[Position[tree[[All, -1]], root]];
    For[i = 1, i <= Length[pos], i++,
        toAdd = Flatten[Thread[{tree[[pos[[i]]]], {#}}]] & /@ nodes;
        (* check cycles!*)            
        If[cycleQ[#] != True, AppendTo[tree, #]] & /@ toAdd;
    ];
    tree = Delete[tree, {#} & /@ pos];
    builtTree[#, matrix] & /@ Union[tree[[All, -1]]];
    ];
];

para llamar al código:initNode = 1;endNode = 6;lcycle = {};árbol = {{initNode}};builtTree[initNode, matriz];

rutas de acceso:{{1}} raíz:1---nodos:{2,3,4}

rutas de acceso:{{1,2},{1,3},{1,4}} raíz:2---nodos:{3,4,5}

rutas de acceso:{{1,3},{1,4},{1,2,3},{1,2,4},{1,2,5}} raíz:3---nodos:{2,4}

rutas de acceso:{{1,4},{1,2,4},{1,2,5},{1,3,4},{1,2,3,4},{1,3,2,4},{1,3,2,5}} raíz:4---nodos:{2,3,6}

rutas de acceso:{{1,2,5},{1,3,2,5},{1,4,6},{1,2,4,6},{1,3,4,6},{1,2,3,4,6},{1,3,2,4,6},{1,4,2,5},{1,3,4,2,5},{1,4,3,2,5}} raíz:5---nodos:{6}

RESULTADOS:{{1, 4, 6}, {1, 2, 4, 6}, {1, 2, 5, 6}, {1, 3, 4, 6}, {1, 2, 3, 4, 6}, {1, 3, 2, 4, 6}, {1, 3, 2, 5, 6}, {1, 4, 2, 5, 6}, {1, 3, 4, 2, 5, 6}, {1, 4, 3, 2, 5, 6}}

...Lamentablemente no puedo subir imágenes a mostrar los resultados en una forma mejor :(

http://textanddatamining.blogspot.com

Lo que estamos tratando de hacer es esencialmente para encontrar un camino entre dos vértices en un grafo (dirigido?) Echa un vistazo a el algoritmo de Dijkstra si necesita camino más corto o escribir una función recursiva sencilla si necesita cualquier existen caminos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top