Najít cesty mezi dvěma danými uzly?

hlasů
42

Řekněme, že mám uzly připojené v následující módy, jak se mohu dospět k počtu cest, které existují mezi zadanými body a detaily cesty?

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

Najít cesty od 1-7:

Odpověď: nalezeno 2 cesty a jsou

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

alt

Implementace našel tady je pěkná Chystám se používají stejné

Zde je úryvek z výše uvedeného odkazu v pythonu

# 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']
Položena 03/04/2009 v 12:09
zdroj uživatelem
V jiných jazycích...                            


8 odpovědí

hlasů
-3

Co se snažíte udělat, je v podstatě najít cestu mezi dvěma vrcholy v režii (?) Grafu vyzkoušet Dijkstrova algoritmu , pokud budete potřebovat nejkratší cestu nebo napsat jednoduchý rekurzivní funkce, pokud budete potřebovat, co existují cesty.

Odpovězeno 03/04/2009 v 12:14
zdroj uživatelem

hlasů
33

Prohledávání do šířky prochází graf a ve skutečnosti nalezne všechny cesty z výchozího uzlu. Obvykle BFS nedrží všechny cesty, nicméně. Místo toho aktualizuje funkce prededecessor n zachránit nejkratší cestu. Můžete snadno měnit algoritmus, takže π(n)není jen uložit jednu předchůdce, ale seznam možných předchůdců.

Pak všechny možné cesty jsou zakódovány v této funkci, a pojížděním n rekurzivně dostanete všechny možné kombinace cest.

Jeden dobrý pseudokód, který využívá tento zápis lze nalézt v Úvod do algoritmů podle CORMEN et al. a následně byl použit v mnoha univerzitních skriptech na toto téma. Vyhledá na Googlu „BFS pseudocode předchůdce π“ vyvrací tento hit o stoh papírů .

Odpovězeno 03/04/2009 v 12:38
zdroj uživatelem

hlasů
1

Pokud chcete, všechny cesty, používat rekurzi.

Použití seznamu sousednosti, nejlépe vytvořit funkci f (), který se snaží vyplnit aktuální seznam navštívených vrcholů. Jako tak:

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

Vzhledem k tomu, že vektor je předán hodnotu (a tím i všechny změny provedené dále v rekurzivní procedury nejsou trvalé), všechny možné kombinace jsou vyjmenovány.

Můžete získat trochu účinnosti předáním předchozí vektor s odkazem (a tudíž není třeba kopírovat vektor znovu a znovu), ale budete muset zajistit, aby se věci popped_back () manuálně.

Ještě jedna věc: v případě, že graf má cykly, že to nebude fungovat. (Předpokládám, že v tomto případě budete chtít najít všechny jednoduché cesty, pak) Před přidáním něco do předchozího vektoru, nejprve zkontrolujte, zda je to už tam.

Pokud chcete, všechny nejkratší cesty, použijte Konrad je návrh s tímto algoritmem.

Odpovězeno 03/04/2009 v 12:45
zdroj uživatelem

hlasů
7

Dijkstrův algoritmus platí více vážených cest a zní to jako plakát se chtějí najít všechny cesty, a to nejen nejkratší.

Pro tuto aplikaci, tak bych vybudovat graf (aplikace vypadá, že by nebylo třeba směřovat) a používat svůj oblíbený způsob vyhledávání. Vypadá to, že chcete, aby všechny cesty, ne jen hádat v nejkratší, takže použít jednoduchý rekurzivní algoritmus dle vlastního výběru.

Jediným problémem je to v případě, že graf může být cyklická.

S připojením:

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

Při hledání cesty z 1-> 4, mohli byste mít cyklus 1 -> 2 -> 3 -> 1.

V tomto případě, pak bych udržet stoh jako přecházení uzly. Zde je seznam s kroky pro tento graf a výsledný zásobníku (omlouvám se za formátování - žádný option tabulka):

aktuální uzel (případné další uzly minus, odkud jsme přišli) [stack]

  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] // chyba - duplicitní číslo v zásobníku - zjištěn cyklus
  5. 3 () [1, 2, 3] // zpětně vstoupil do uzlu tři a odebere 1 z hromádky. Žádné další uzly prozkoumat odtud
  6. 2 (4) [1, 2] // back-přistoupil k uzlu 2 a odebere 1 z hromádky.
  7. 4 () [1, 2, 4] // Cílový uzel nalezeno - Záznam zásobník pro cestu. Žádné další uzly prozkoumat odtud
  8. 2 () [1, 2] // back-přistoupil k uzlu 2 a odebere 4 z hromádky. Žádné další uzly prozkoumat odtud
  9. 1 (3) [1] // back-přistoupil k uzlu 1 a odebere 2 z fronty.
  10. 3 (2) [1, 3]
  11. 2 (1, 4) [1, 3, 2]
  12. 1 (2, 3) [1, 3, 2, 1] // chyba - duplicitní číslo v zásobníku - zjištěn cyklus
  13. 2 (4) [1, 3, 2] // zpětně přistoupil k uzlu 2 a odebere 1 z hromádky
  14. 4 () [1, 3, 2, 4] Cílový uzel nalezeno - Záznam zásobník pro cestu. Žádné další uzly prozkoumat odtud
  15. 2 () [1, 3, 2] // back-přistoupil k uzlu 2 a odebere 4 z hromádky. Žádné další uzly
  16. 3 () [1, 3] // back-přistoupil k uzlu 3 a odebere 2 z fronty. Žádné další uzly
  17. 1 () [1] // back-přistoupil k uzlu 1 a odebere 3 z hromádky. Žádné další uzly
  18. Provádí se 2 zaznamenaných cestami [1, 2, 4] a [1, 3, 2, 4]
Odpovězeno 03/04/2009 v 12:52
zdroj uživatelem

hlasů
3

Původní kód je trochu těžkopádný a budete chtít použít collections.deque místo Chcete-li používat BFS zjistit, zda existuje cesta mezi 2 body na grafu. Zde je rychlé řešení I hacknutý up:

Poznámka: Tato metoda by mohla pokračovat nekonečně, pokud neexistuje žádná cesta mezi dvěma uzly. I nebyly testovány všechny případy, 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)
Odpovězeno 20/07/2009 v 03:22
zdroj uživatelem

hlasů
22

Pro ty, kteří nejsou PYTHON expert, stejný kód v jazyce 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 ]


*/
Odpovězeno 04/06/2012 v 20:17
zdroj uživatelem

hlasů
2

dána matice sousednosti:

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

Následující kód Wolfram Mathematica vyřešit problém najít všechny jednoduché cesty mezi dvěma uzly grafu. Použil jsem jednoduchý rekurzi a dvě globální var sledovat cykly a ukládat požadovaný výkon. kód nebyl optimalizován právě kvůli kódu jasnosti. „tiskový“ by měla být užitečné objasnit, jak to funguje.

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

volat kód: initNode = 1; endNode = 6; lcycle = {}; strom = `initNode`; builtTree [initNode, matice];

Cesty: `1` kořen: 1 --- uzly: {2,3,4}

Cesty: {{1,2}, {1,3}, {1,4}} kořen: 2 --- uzly: {3,4,5}

Cesty: {{1,3}, {1,4}, {1,2,3}, {1,2,4}, {1,2,5}} kořen: 3 --- uzly: {2, 4}

Cesty: {{1,4}, {1,2,4}, {1,2,5}, {1,3,4}, {1,2,3,4}, {1,3,2, 4}, {1,3,2,5}} kořen: 4 --- uzly: {2,3,6}

Cesty: {{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}} kořen: 5 --- uzly: {6}

Výsledky: {{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}}

... Bohužel nemohu nahrát obrázky zobrazovat výsledky v lepším způsobem :(

http://textanddatamining.blogspot.com

Odpovězeno 23/08/2012 v 19:58
zdroj uživatelem

hlasů
3

V Prolog (konkrétně 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.
Odpovězeno 15/09/2016 v 12:02
zdroj uživatelem

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