Găsiți căile între două noduri date?

voturi
42

Să presupunem că am noduri conectate în moda de mai jos, cum pot ajunge la numărul de căi care există între puncte date și detaliile de cale?

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

Găsiți căile de la 1 la 7:

Răspuns: 2 căi găsite și ele sunt

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

alt

punerea în aplicare a găsit aici este frumos am de gând să folosească același lucru

Iată fragmentul din link-ul de mai sus în 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']
Întrebat 03/04/2009 la 12:09
sursa de către utilizator
În alte limbi...                            


8 răspunsuri

voturi
-3

Ceea ce încercăm să facem este , în esență , să găsească o cale între două noduri într - un grafic (regia?) Verifica algoritmul Dijkstra dacă aveți nevoie de calea cea mai scurtă sau de a scrie o funcție recursivă simplu , dacă aveți nevoie de orice există căi.

Publicat 03/04/2009 la 12:14
sursa de către utilizator

voturi
33

Breadth-first traversează un grafic și , de fapt , găsește toate căile dintr - un nod de pornire. De obicei, BFS nu păstrează toate căile, cu toate acestea. In schimb, ea actualizează o funcție π prededecessor pentru a salva calea cea mai scurtă. Aveți posibilitatea să modificați cu ușurință algoritmul , astfel încât π(n)nu stochează doar un singur predecesor , ci o listă de posibile predecesorii.

Apoi, toate căile posibile sunt codificate în această funcție, și traversand tt recursiv veți obține toate combinațiile posibile de cale.

Un pseudocode bun care folosește această notație poate fi găsită în Introducere în Algoritmi de Cormen et al. și ulterior a fost folosit în multe scripturi universitare pe acest subiect. O căutare Google pentru „BFS pseudocod predecesorul π“ dezrădăcinează acest hit pe stivă de schimb .

Publicat 03/04/2009 la 12:38
sursa de către utilizator

voturi
1

Dacă doriți ca toate căile, utilizați recursivitate.

Folosind o listă adjacency, de preferință, să creați o funcție f (), care încearcă să completeze lista curentă de noduri vizitate. Ca astfel:

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);
}

Datorită faptului că vectorul este trecut prin valoare (și, prin urmare, orice modificări efectuate în continuare în cadrul procedurii recursive nu sunt permanente), toate combinațiile posibile sunt enumerate.

Puteți obține un pic de eficiență prin trecerea anterioară vectorul de referință (și , prin urmare , nu au nevoie să copieze vectorul peste si peste din nou) , dar va trebui să vă asigurați că lucrurile se popped_back () manual.

Încă un lucru: dacă graficul are cicluri, acest lucru nu va funcționa. (Presupun că , în acest caz , veți dori să găsească toate simplu căi, atunci) Înainte de a adăuga ceva în precedent vector, verificați mai întâi dacă este deja acolo.

Dacă doriți ca toate cele mai scurte căi, utilizați sugestia Konrad cu acest algoritm.

Publicat 03/04/2009 la 12:45
sursa de către utilizator

voturi
7

Algoritmul Dijkstra se aplică mai mult pentru căi ponderate și se pare că afișul a fost doresc să găsească toate căile, nu doar cel mai scurt.

Pentru această aplicație, aș construi un grafic (aplicația sună ca nu ar trebui să fie direcționată) și utilizați metoda de căutare preferat. Se pare că doriți ca toate căile, nu doar o presupunere cel mai scurt unul, deci utilizați un algoritm recursiv simplu de alegerea ta.

Singura problema cu acest lucru este în cazul în care graficul poate fi ciclic.

Cu conexiuni:

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

In timp ce cauta o cale de la 1-> 4, ai putea avea un ciclu de 1 -> 2 -> 3 -> 1.

În acest caz, atunci aș păstra o stivă ca traversează nodurile. Iată o listă cu pașii pentru acest grafic și stiva rezultat (scuze pentru formatarea - nici o opțiune de masă):

nodul curent (noduri posibile pentru următoarele minus în cazul în care am venit de la) [stivă]

  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] // eroare - duplicat număr pe stivă - ciclu detectat
  5. 3 () [1, 2, 3] // regresul în trepte la nodul trei și readusa 1 de pe stivă. Nu mai multe noduri pentru a explora de aici
  6. 2 (4) [1, 2] // back-trepte pentru nodul 2 și readusa 1 de pe stivă.
  7. 4 () [1, 2, 4] // nod țintă a găsit - stiva record pentru o cale. Nu mai multe noduri pentru a explora de aici
  8. 2 () [1, 2] // back-trepte la nodul 2 și readusa 4 de pe stivă. Nu mai multe noduri pentru a explora de aici
  9. 1 (3) [1] // back-trepte la nodul 1 și readusa 2 de pe stivă.
  10. 3 (2) [1, 3]
  11. 2 (1, 4) [1, 3, 2]
  12. 1 (2, 3) [1, 3, 2, 1] // eroare - duplicat număr pe stivă - ciclu detectat
  13. 2 (4) [1, 3, 2] // regresul în trepte la nodul 2 și readusa 1 de pe stivă
  14. 4 () [1, 3, 2, 4] nod Target a găsit - stiva record pentru o cale. Nu mai multe noduri pentru a explora de aici
  15. 2 () [1, 3, 2] // back-trepte la nodul 2 și readusa 4 de pe stivă. Nu există mai multe noduri
  16. 3 () [1, 3] // back-trepte la nodul 3 și readusa 2 de pe stivă. Nu există mai multe noduri
  17. 1 () [1] // back-trepte la nodul 1 și readusa 3 de pe stivă. Nu există mai multe noduri
  18. Efectuat cu 2 căi înregistrate de [1, 2, 4] și [1, 3, 2, 4]
Publicat 03/04/2009 la 12:52
sursa de către utilizator

voturi
3

Codul original este un pic greoaie și ați putea dori să utilizați collections.deque în schimb, dacă doriți să utilizați BFS pentru a găsi în cazul în care există o cale între 2 puncte pe grafic. Aici este o soluție rapidă am intrat în sus:

Notă: această metodă s-ar putea continua la infinit, dacă nu există nici o cale între cele două noduri. Nu am testat toate cazurile, YMMV.

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)
Publicat 20/07/2009 la 03:22
sursa de către utilizator

voturi
22

Pentru cei care nu sunt expert PYTHON, același cod în 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 ]


*/
Publicat 04/06/2012 la 20:17
sursa de către utilizator

voturi
2

dat matricea de adiacenta:

{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}

următorul cod de Wolfram Mathematica rezolva problema pentru a găsi toate căile simple între două noduri ale unui grafic. Am folosit recursie simplu, și două var la nivel mondial pentru a ține evidența ciclurilor și pentru a stoca rezultatul dorit. codul nu a fost optimizat doar de dragul de cod claritate. „Print“ ar trebui să fie de ajutor pentru a clarifica modul în care funcționează.

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]]];
    ];
];

pentru a apela codul: initNode = 1; endNode = 6; lcycle = {}; copac = `initNode`; builtTree [initNode, matricea];

căi: `1` rădăcină: 1 --- noduri: {2,3,4}

căi: {{1,2}, {1,3}, {1,4}} root: 2 --- noduri: {3,4,5}

căi: {{1,3}, {1,4}, {1,2,3}, {1,2,4}, {1,2,5}} rădăcină: 3 --- noduri: {2, 4}

căi: {{1,4}, {1,2,4}, {1,2,5}, {1,3,4}, {1,2,3,4}, {1,3,2, 4}, {1,3,2,5}} root: 4 --- noduri: {2,3,6}

căi: {{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}} rădăcină: 5 --- noduri: {6}

REZULTATE: {{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}}

... Din păcate, nu pot încărca imagini pentru a afișa rezultatele într-un mod mai bun :(

http://textanddatamining.blogspot.com

Publicat 23/08/2012 la 19:58
sursa de către utilizator

voturi
3

În Prolog (în mod specific, 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).

Test:

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.
Publicat 15/09/2016 la 12:02
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more