Znaleźć ścieżki między dwoma węzłami podanych?

głosy
42

Muszę powiedzieć węzłów połączonych w poniższej mody, w jaki sposób dotrzeć do wielu ścieżek, które istnieją pomiędzy danymi punktami, a także danych o trasie?

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

Odnaleźć ścieżki od 1 do 7:

Odpowiedź: znaleziono 2 ścieżki i są

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

tekst

Realizacja znaleźć tutaj jest ładne mam zamiar korzystać z tego samego

Oto fragment z powyższego linku w 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']
Utwórz 03/04/2009 o 12:09
źródło użytkownik
W innych językach...                            


8 odpowiedzi

głosy
-3

Co starasz się zrobić to w zasadzie znaleźć drogę między dwoma wierzchołkami w reżyserii (?) Wykresu sprawdzeniu Algorytm Dijkstry jeśli trzeba najkrótszą ścieżkę lub napisać prostą funkcję rekurencyjną jeśli trzeba cokolwiek istnieć ścieżki.

Odpowiedział 03/04/2009 o 12:14
źródło użytkownik

głosy
33

Przeszukiwanie wszerz przechodzi wykres w rzeczywistości wyszukuje wszystkie ścieżki od węzła wyjściowego. Zazwyczaj BFS nie przechowuje wszystkie ścieżki, jednak. Zamiast tego aktualizuje gatunku funkcji prededecessor aby zapisać najkrótszą drogę. Można łatwo zmodyfikować algorytm tak, że π(n)nie tylko przechowywać jeden poprzednik, ale listę możliwych poprzedników.

Wtedy wszystkie możliwe ścieżki są kodowane w tej funkcji, a przez przejeżdżające gatunku rekurencyjnie można uzyskać wszystkie możliwe kombinacje ścieżki.

Jeden dobry pseudokod, który korzysta z tej notacji można znaleźć w Wprowadzenie do algorytmów przez Cormen et al. i zostało następnie wykorzystane w wielu skryptów uniwersyteckich na ten temat. Wyszukiwarka Google dla „BFS pseudokod poprzednik π” zmiata to trafienie na stosie Exchange .

Odpowiedział 03/04/2009 o 12:38
źródło użytkownik

głosy
1

Jeśli chcesz wszystkie ścieżki, użyj rekursji.

Korzystanie z listy przylegania korzystnie utworzyć funkcję f (), które próbuje wypełnić bieżącej listy odwiedzonych wierzchołków. 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);
}

Ze względu na fakt, że wektor jest przekazywane przez wartość (a więc wszelkie zmiany wprowadzone w dalszej części procedury rekurencyjne nie są trwałe), wszystkie możliwe kombinacje są wyliczone.

Można zyskać trochę efektywności poprzez przepuszczenie poprzedni wektor odnośnik (a więc nie konieczności ponownie skopiować wektor kółko), ale musisz upewnić się, że robi się popped_back () ręcznie.

I jeszcze jedno: jeśli wykres ma cykli, to nie będzie działać. (Zakładam, że w tym przypadku będziemy chcieli znaleźć wszystkie prostych ścieżek, wtedy) Przed dodaniem czegoś do poprzedniego wektora, najpierw sprawdzić, czy jest już w środku.

Jeśli chcesz, aby wszystkie najkrótsze ścieżki, użyj sugestii Konrada z tego algorytmu.

Odpowiedział 03/04/2009 o 12:45
źródło użytkownik

głosy
7

Algorytm Dijkstry dotyczy więcej ważonych ścieżek i brzmi jak plakat został chcąc znaleźć wszystkie ścieżki, a nie tylko najkrótszy.

Z tego wniosek, że mogę zbudować wykres (aplikacja brzmi jakby nie musiałyby być kierowane) i użyć ulubionego metodę wyszukiwania. Brzmi to jak chcesz wszystkie ścieżki, a nie tylko zgadywać co najkrótsza, więc użyć prostego rekurencyjny algorytm wyboru.

Jedyny problem polega na tym, że wykres może być cykliczne.

Z przyłączami:

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

Patrząc na ścieżce z 1-> 4, można mieć cykl 1 -> 2 -> 3 -> 1.

W tym przypadku, to bym zachować stos jak przejeżdżające węzły. Oto lista z etapów tego wykresu i powstałego stosu (przepraszam za brak opcji formatowania - tabela):

bieżący węzeł (ewentualne kolejne węzły minus skąd jesteśmy) [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] // błąd - powtarzający się numer w stos - wykryto cykl
  5. 3 () [1, 2, 3] // back-wszedł do węzła trzy i pojawiło 1 od stosu. Nie więcej węzłów zbadać stąd
  6. 2 (4) [1, 2] // back-podszedł do węzła 2, pojawiło 1 ze stosu.
  7. 4 () [1, 2, 4] // docelowy węzeł znaleziono - płyta stos na ścieżce. Nie więcej węzłów zbadać stąd
  8. 2 () [1, 2] // back-podszedł do węzłów 2 i 4 pojawiła się w stos. Nie więcej węzłów zbadać stąd
  9. 1 (3) [1] // back-podszedł do węzła 1 i 2 pojawiło się w stos.
  10. 3 (2) [1, 3]
  11. 2 (1, 4) [1, 3, 2]
  12. 1 (2, 3) [1, 3, 2, 1] // błąd - powtarzający się numer w stos - wykryto cykl
  13. 2 (4) [1, 3, 2] // back-podszedł do węzła 2, pojawiło 1 ze stosu
  14. 4 () [1, 3, 2, 4] Docelowy węzeł znaleziono - płyta stos na ścieżce. Nie więcej węzłów zbadać stąd
  15. 2 () [1, 3, 2] // back-podszedł do węzłów 2 i 4 pojawiła się w stos. Brak więcej węzłów
  16. 3 () [1, 3] // back-podszedł do węzła 3, pojawiło 2 ze stosu. Brak więcej węzłów
  17. 1 () [1] // back-podszedł do węzła 1 i 3 pojawiło się w stos. Brak więcej węzłów
  18. Sporządzono 2 zapisanych ścieżek [1, 2, 4] i [1, 3, 2, 4]
Odpowiedział 03/04/2009 o 12:52
źródło użytkownik

głosy
3

Oryginalny Kod jest nieco kłopotliwe, a może chcesz użyć collections.deque zamiast jeśli chcesz korzystać z BFS do znalezienia, jeśli istnieje ścieżka między 2 punkty na wykresie. Oto szybkie rozwiązanie I włamał się:

Uwaga: ta metoda może kontynuować w nieskończoność, jeśli nie istnieje ścieżka pomiędzy dwoma węzłami. Nie testowałem wszystkie przypadki, 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)
Odpowiedział 20/07/2009 o 03:22
źródło użytkownik

głosy
22

Dla tych, którzy nie są ekspertami Python, ten sam kod w 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 ]


*/
Odpowiedział 04/06/2012 o 20:17
źródło użytkownik

głosy
2

biorąc pod uwagę macierz sąsiedztwa:

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

ten kod Wolfram Mathematica rozwiązać problem znalezienia wszystkich prostych odcinków między dwoma węzłami wykresu. Kiedyś rekursji prostej, a dwa globalnego var śledzić cykli i przechowywanie pożądany wynik. kod nie został zoptymalizowany właśnie przez wzgląd na przejrzystość kodu. „Print” powinny być pomocne w celu wyjaśnienia, jak to działa.

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

zadzwonić kod: initNode = 1; endNode = 6; lcycle = {}; drzewo = `initNode`; builtTree [initNode, matryca];

Ścieżki: `1 'rdzeniu: 1 --- węzły: {2,3,4}

Ścieżki: {{1,2}, {1,3}, {1,4}} główny 2 --- węzły: {3,4,5}

Ścieżki: {{1,3}, {1,4}, {1,2,3}, {1,2,4}, {1,2,5}} korzeniowe: 3 --- węzły: {2, 4}

Ścieżki: {{1,4}, {1,2,4}, {1,2,5}, {1,3,4}, {1,2,3,4}, {1,3,2, 4}, {1,3,2,5}} główny: 4 --- węzły: {2,3,6}

Ścieżki: {{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}} korzeniowe: 5 --- węzły: {6}

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

... Niestety nie mogę przesłać zdjęcia, aby pokazać wyniki w lepszy sposób :(

http://textanddatamining.blogspot.com

Odpowiedział 23/08/2012 o 19:58
źródło użytkownik

głosy
3

W startowych (konkretnie SWI Prologa)

:- 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.
Odpowiedział 15/09/2016 o 12:02
źródło użytkownik

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