Documente Academic
Documente Profesional
Documente Cultură
Cu titlu de manuscris
C.Z.U:
DASCAL ANDRIAN
Aprobat:
CHIȘINĂU, 2019
Cuprins
Introducere ........................................................................................................................................ 3
CAPITOLUL 1 .................................................................................................................................. 4
ABORDĂRI METODICE PRIVIND STUDIEREA ALGORITMULUI LEE ..................................... 4
1. Prezentare generală a algoritmului Lee ............................................................................... 4
2. Domenii de aplicativitate a algoritmului Lee. ...................................................................... 5
3. Analiza algoritmului Lee pentru soluționarea problemei labirintului. ............................... 6
4. Implementarea algoritmului Lee în limbajul C++ pentru problema labirintului. ............. 9
5. Implementarea algoritmului Lee în Matlab. ......................................................................11
CAPITOLUL 2 .................................................................................................................................13
ABORDĂRI METODICE PRIVIND STUDIEREA ALGORITMULUI BELLMAN-FORD .............13
1. Prezentare generală a algoritmului Bellman-Ford .............................................................13
2. Domenii de aplicativitate a algoritmului Bellman-Ford .....................................................14
3. Analiza algoritmului Bellman-Ford ....................................................................................15
4. Implementarea algoritmului Bellman-Ford în limbajul C++ ............................................17
5. Implementarea algoritmului Bellman-Ford în Matlab. .....................................................20
Concluzii ..........................................................................................................................................22
Bibliografie.......................................................................................................................................23
2
Introducere
Un graph este un desen planificat, format din linii, care se referă la numere între ele.
Scopul unui graph este de a prezenta date prea numeroase sau complicate pentru a fi descrise
în mod adecvat în text și în mai puțin spațiu.
Obiectivul acestei lucrări este de a aborda unele aspect metodice privind unitățile de
conținut: Algoritmul Lee și Algoritmul Bellman-Ford. Tot aici voi prezenta importanța și
relevanța teoriei graph-urilor în diverse domenii, cum ar fi matematica pură, informatică,
sociologie, cercetare operațională și alte aplicații științifice. Există o serie de alte domenii de
aplicație interesante în care teoria graficului a jucat un rol vital.
Graph-urile facilitează vizibilitatea informațiilor. Acest lucru este valabil mai ales atunci
când două sau mai multe seturi de numere sunt corelate într-un fel. Când facem calcule în
viața de zi cu zi, avem nevoie de cunoștințele de bază pentru a utiliza graph-uri. Nu este doar
pentru cei care excelează în matematică, ci pentru fiecare elev să folosească în funcție de
nevoile lor. Atunci când facem analize de orice fel, trebuie să folosim structura. Acest lucru se
va face folosind un graph. Chiar și planificarea bugetului dvs. lunar poate fi beneficiată prin
întocmirea unui graph, faceți acest lucru pentru o perioadă de 6 luni și în curând veți putea
vedea unde greșiți și unde prosperați.
Graficele sunt utilizate în viața de zi cu zi, de la ziarul local până la standul de reviste.
Este una dintre acele abilități pe care pur și simplu nu le poți face fără. Oricare ar fi nevoia
sau calculul dvs., dacă este utilizat corect, un graph vă poate ajuta și vă simplifica
viața.Contabilii vor beneficia prin utilizarea graph-urilor pentru a transmite informații
financiare clienților lor. Un graph poate fi foarte util în colectarea și stocarea datelor într-un
singur loc.
Analiza critică a literaturii de specialitate privind natura, specificul, avantajele şi limitele,
precum şi criteriile de alegere ale unei abordări cantitative sau calitative a permis, pe de o
parte, evidenţierea şi susţinerea valorii complementare a utilizării lor combinate într-o
structură metodologică complexă, iar pe de altă parte, trasarea elementelor cadru ale unei
metodologii de cercetare mixte.
Pentru a răspunde la dificila provocare de a analiza metodele calitative și cantitative în
perspectiva integrării lor într-un sistem coerent, s-a avut în vedere faptul că unele metode sunt
utile pentru a atinge obiective specifice pe diferite etape ale cercetării, dar şi că limitele
inerente unei anumite metode pot fi compensate de avantajele alteia.
3
CAPITOLUL 1
ABORDĂRI METODICE PRIVIND STUDIEREA ALGORITMULUI
LEE
5
Problema labirintului.
Vom utiliza o matrice mat, cea pe care o citim, și pe care o vom folosi de asemenea
pentru a calcula niște rezultate parțiale despre care voi vorbi imediat. Avem nevoie și de o
coadă q, cu elemente de tip Pos. Tipul Pos este un struct pentru reținerea coordonatelor
celulelor din matrice. Acesta conține câmpurile lin și col, pentru linia și coloana poziției
stocate.
OBSERVAȚII:
Algoritmul lui Lee presupune doi paşi importanţi:
1. Primul şi poate cel mai important pas este folosirea unei cozi, sub forma unui vector de
structuri (de preferabil), care va menţine toţi paşii pe care o să-i facem de acum în colo.
În această coadă se pun, pentru fiecare pas, locurile care s-au marcat la punctul anterior.
2. Se marchează cu numere consecutive toate locurile posibile prin care putem trece,
parcurgând în ordine elementele cozii, până când nu mai putem marca, sau am ajuns la
final.
6
Descrierea succintă a celor 4 etape de implementare a algoritmului Lee:
1. Initializare
Selectați punctul de pornire, marcați cu 0
i: = 0
2. Extinderea valurilor
REPETĂ
o Marcați toți vecinii nemarcati ai punctelor marcate cu i cu i +1
o i: = i + 1
ÎN FINAL ((obiectiv atins) sau (nu se pot marca puncte))
3. Backtrace (întoarcerea)
mergeți la punctul țintă
REPETĂ
o mergeți la următorul nod care are o notă mai mică decât nodul curent
o adăugați acest nod la cale
ÎN FINAL (punctul de pornire atins)
OBSERVAȚII:
1. În coada q se adaugă poziția șoarecelui.
2. Se completează această poziție din mat cu valoarea 1.
3. Cât timp coada nu este vidă și nici nu am găsit lungimea minimă:
Extragem primul element din coadă. Să-i zicem pos.
Îi parcurgem vecinii din matrice, dacă vecinul curent este accesibil și nevizitat, atunci
îl marcăm drept vizitat, completând celula sa corespunzătoare din mat cu
valoarea mat[pos.lin][pos.col] + 1, apoi îl introducem în coadă.
4. Afișăm valoarea din mat de pe poziția unde se află bucata de brânză.
IMPORTANT:
1. Complexitatea algoritmului este O(m⋅n)O(m⋅n), deoarece fiecare celulă a matricei este
vizitată maxim o singură dată. Această complexitate este extrem de bună, având în
vedere dimensiunile input-ului.
2. Problema se poate rezolva şi cu ajutorul metodei backtracking, dar nu este metoda cea
mai eficientă, complexitatea fiind O(4(M*N)), sau O(3(M*N)) după caz, ceea ce este foarte
mult. În primul pas vom pune în coadă coordonatele locului de plecare, urmând apoi să
parcurgem pe rând coada, până când nu mai există cale de ieşire sau am găsit una.
7
Explicația algoritmului
În timpul execuției algoritmului, în matricea mat, o poziție are valoarea -1 dacă este
inaccesibilă, 0 dacă încă nu a fost vizitată, sau distanța minimă de la șoarece la ea altfel.
Algoritmul lui Lee se bazează pe următoarea idee: Dacă știm lungimea drumului optim de la
șoarece până la poziția accesibilă de coordonate i și j (mat[i][j]), putem actualiza lungimile
drumurilor minime pentru vecinii accesibili (și nevizitați încă) ai ei; aceste valori vor fi egale
cu mat[i][j] + 1, pentru că de la poziția (i, j) până la un vecin de-ai ei se mai face un singur
pas. Asta e practic o relație de recurență, așa că Algoritmul lui Lee poate fi considerat un
algoritm de programare dinamică.
Totuși, recurența asta nu e suficientă. Mai trebuie să ținem cont de ordinea în care
completăm matricea mat. După ce am completat toate celulele din mat cu valoarea x (cele
până la care se poate ajunge în minim x pași), trebuie să completăm lungimile minime
pentru vecinii lor (cu x + 1), apoi pentru vecinii vecinilor lor (cu x + 2), și tot așa. Doar în
acest fel putem fi siguri că toate rezultatele din mat sunt corecte. Completarea matricei poate
fi asemănată cu modul în care o picătură de cerneală se extinde pe o bucată de hârtie.
Pentru a menține această ordine a completării matricei, se folosește o coadă, căci această
structură de date funcționează pe principiul primul venit, primul servit. La fiecare pas, din
coadă extragem primul element pentru a-l prelucra (a completa lungimile corespunzătoare
vecinilor accesibili și a-i pune la sfârșitul cozii). Întotdeauna, o parte dintre pozițiile din coadă
(primele) vor avea o anumită valoare, iar restul (vecinii lor) vor avea valoarea cu o unitate mai
mare.
Tabelul 1 – Date de intrare / Date de ieșire
8
NOTĂ:
1. Datele corespunzătoare problemei le-am scris într-un fișier, astfel am reprezentat cu 0 -
pozițiile accesibile, iar cu -1 am marcat pozițiile inaccesibile.
2. Rândul 12 din fișier ne reprezintă poziția șoarecelui, iar rândul 13 din fișier ne reprezintă
poziția brânzei (vezi Tabelul 1).
Vom elabora o librărie în care vom include toate subprogramele de care avem nevoie
pentru a obține soluția problemei labirintului. Ca rezultat final am elaborat librăria cu numele
Lee.h
#ifndef LEE_H_INCLUDED
#define LEE_H_INCLUDED
#include <fstream>
#define DMAX 618
using namespace std;
ifstream fin("lee.txt");
ofstream fout("lee.out");
Vom elabora un program ce va aplica această librărie pentru a obține soluția problemei
labirintului. Ca rezultat final am elaborat programul Lee.cpp
#include <iostream>
#include "Lee.h"
int main() {
scan();
surround(); //functia obstacol
lee();
print();
fout.close();
return 0;
}
NOTĂ:
După execuția codului de program C++ în conformitate cu datele de intrare (vezi Tabelul 1)
obținem soluția problemei: drumul minim (vezi imagine 4).
10
5. Implementarea algoritmului Lee în Matlab.
Exemplul 1 - Găsirea tuturor căilor cele mai scurte într-un graph direcționat.
Rezolvare:
1. Creați și vizualizați un grafic direcționat cu 6 noduri și 11 muchii.
2. Găsiți toate cele mai scurte căi între fiecare pereche de noduri în graph-ul direcționat.
Funcția în Matlab:
function [ output_args ] = Untitled( input_args )
W = [.41 .99 .51 .32 .15 .45 .38 .32 .36 .29 .21];
DG = sparse([6 1 2 2 3 4 4 5 5 6 1],[2 6 3 5 4 1 6 3 4 3 5],W)
view(biograph(DG,[],'ShowWeights','on'))
graphallshortestpaths(DG)
end
Soluția
Observație:
Matricea rezultată arată cea mai scurtă cale de la nodul
1 (primul rând) la nodul 6 (a șasea coloană) este 0,95.
Puteți vedea acest lucru în grafic urmărind calea de la
nodul 1 la nodul 5 la nodul 4 până la nodul 6 (0,21 +
0,36 + 0,38 = 0,95).
Exemplul 2 - Găsirea tuturor căilor cele mai scurte într-un graph nedirecționat.
Rezolvare:
1. Creați și vizualizați un grafic nedirecționat cu 6 noduri și 11 muchii.
2. Găsiți toate cele mai scurte căi între fiecare pereche de noduri în graph-ul nedirecționat.
Funcția în Matlab:
function [ output_args ] = Untitled( input_args )
W = [.41 .99 .51 .32 .15 .45 .38 .32 .36 .29 .21];
DG = sparse([6 1 2 2 3 4 4 5 5 6 1],[2 6 3 5 4 1 6 3 4 3 5],W)
UG = tril(DG + DG')
view(biograph(UG,[],'ShowArrows','off','ShowWeights','on'))
graphallshortestpaths(UG,'directed',false)
end
11
Soluția
Observație:
Matricea rezultată este simetrică deoarece
reprezintă un grafic nedirecționat. Acesta arată că
cea mai scurtă cale de la nodul 1 (primul rând) la
nodul 6 (a șasea coloană) este 0,83. Puteți vedea
acest lucru în grafic urmărind calea de la nodul 1 la
nodul 4 până la nodul 6 (0,45 + 0,38 = 0,83).
Deoarece UG este un grafic nedirecționat, putem
folosi marginea dintre nodul 1 și nodul 4, lucru pe
care nu l-am putut face în graficul direcționat DG.
12
CAPITOLUL 2
ABORDĂRI METODICE PRIVIND STUDIEREA ALGORITMULUI
BELLMAN-FORD
Algoritmul Bellman-Ford este un algoritm de căutare în graph care calculează cele mai
scurte căi de la un vertex (vârf) unic sursă la toate celelalte vârfuri dintr-un graph ponderat.
Acest algoritm poate fi utilizat atât pe grafice ponderate, cât și pe cele neponderate.
Algoritmul a fost propus pentru prima dată de Alfonso Shimbel (1955), dar în schimb este
numit după Richard Bellman și Lester Ford, Jr., care l-au publicat în 1958 și respectiv în
1956. Edward F. Moore a publicat același algoritm în 1957, iar din acest motiv este numit
uneori și algoritmul Bellman – Ford – Moore.
Greutățile negative ale marginilor se găsesc în diferite aplicații ale graph-urilor, de unde și
utilitatea acestui algoritm. Dacă un graph conține un „ciclu negativ” (adică un ciclu ale cărui
muchii se însumează la o valoare negativă) accesibilă de la sursă, atunci nu există o cale mai
ieftină: orice cale care are un punct pe ciclul negativ poate fi făcută mai ieftină cu încă o
plimbare în jurul ciclului negativ. Într-un astfel de caz, algoritmul Bellman-Ford poate detecta
și raporta ciclul negativ.
Ca și algoritmul cu cea mai scurtă cale a lui Dijkstra, algoritmul Bellman-Ford este
garantat să găsească cea mai scurtă cale dintr-un grafic. Deși este mai lent decât algoritmul lui
Dijkstra, Bellman-Ford este capabil să manipuleze grafice care conțin greutăți negative ale
marginilor, deci este mai versatil.
Este demn de remarcat faptul că dacă există un ciclu negativ în grafic, atunci nu există cea
mai scurtă cale. Parcurgând ciclul negativ, un număr infinit de ori va continua să scadă costul
căii (chiar dacă lungimea căii este în creștere).
Greutățile negative ale marginilor se găsesc în diferite aplicații ale graficelor, de aici
utilitatea acestui algoritm. Cu toate acestea, dacă un grafic conține un "ciclu negativ", adică
un ciclu ale cărui muchii se însumează la o valoare negativă, atunci nu există o cale mai
ieftină, deoarece orice cale poate fi făcută mai ieftină cu încă o plimbare prin ciclul negativ.
Într-un astfel de caz, algoritmul Bellman-Ford poate detecta cicluri negative și raporta
existența acestora, dar nu poate produce un răspuns „pe cea mai scurtă cale” dacă un ciclu
negativ este accesibil de la sursă.
13
2. Domenii de aplicativitate a algoritmului Bellman-Ford
Problema taxei
Dacă ne-am imagina un scenariu în care trebuie să jucăm baseball la mine acasă. Pe
parcurs, pe fiecare drum, se poate întâmpla unul din două lucruri:
În primul rând, uneori drumul pe care îl utilizați este un drum cu taxă și trebuie să plătiți o
anumită sumă de bani.
În al doilea rând, uneori cineva cunoscut trăiește pe acea stradă (ca un membru al familiei
sau un prieten).
Complexitatea algoritmului
Bellman-Ford face | E | relaxări pentru fiecare iterație și există | V | -1 iterații. Prin
urmare, cel mai rău caz este că Bellman-Ford rulează în timp O (| V | ⋅| E |). Cu toate acestea,
în unele șcenarii, numărul de iterații poate fi mult mai mic.
Pentru anumite graph-uri este nevoie de o singură iterație, prin urmare în cel mai bun caz
de scenariu, este nevoie doar de timp O (| E |). Un exemplu de graph care ar avea nevoie de o
singură rundă de relaxare este un graph în care fiecare vertex se conectează numai la
următorul în mod linear.
Algoritmul Bellman Ford funcționează supraestimând lungimea căii de la vertexul de
pornire la toate celelalte vârfuri. Apoi, relaxează iterativ acele estimări găsind noi căi mai
scurte decât căile supraestimate anterior.
15
Bellman Ford Pseudocode
Trebuie să menținem distanța de cale a fiecărui vertex. Putem stoca asta într-un tablou de
dimensiuni v, unde v este numărul de vârfuri. De asemenea, dorim să putem obține cea mai
scurtă cale, nu numai să cunoaștem lungimea celei mai scurte căi. Pentru aceasta, mapăm
fiecare vertex la vertexul care și-a actualizat ultima lungime a căii.
Odată ce algoritmul s-a încheiat, putem face backtrack de la vârful de destinație la
vertexul sursă pentru a găsi calea.
function bellmanFord(G, S)
for each vertex V in G
distance[V] <- infinite
previous[V] <- NULL
distance[S] <- 0
for each vertex V in G
for each edge (U,V) in G
tempDistance <- distance[U] + edge_weight(U, V)
if tempDistance < distance[V]
distance[V] <- tempDistance
previous[V] <- U
for each edge (U,V) in G
If distance[U] + edge_weight(U, V) < distance[V}
Error: Negative Cycle Exists
return distance[], previous[]
Algoritmul lui Bellman Ford și algoritmul lui Dijkstra sunt foarte similare în structură. În
timp ce Dijkstra privește doar vecinii imediați ai unui vertex, Bellman trece prin fiecare
margine în fiecare iterație (vezi imagine 6).
16
4. Implementarea algoritmului Bellman-Ford în limbajul C++
Problemă
Se dă un graf orientat conex cu N noduri şi M muchii cu costuri. Definim un lanţ ca fiind
un şir de noduri cu proprietatea că între oricare două consecutive există o muchie. Costul unui
lanţ este dat de suma costurilor muchiilor care unesc nodurile ce îl formează. Definim un ciclu
ca fiind un lanţ cu proprietatea că primul element al său este egal cu ultimul. Să se determine
dacă în graful dat există un ciclu de cost negativ. Dacă nu există, să se determine costul minim
al unui lanţ de la nodul 1 la fiecare dintre nodurile 2, 3, ... , N-1, N.
17
coada.pop();
esteincoada[nodcurent] = 0;
for(size_t i=0;i<graf[nodcurent].size();i++)
{
int vecin = graf[nodcurent][i].first;
int cost = graf[nodcurent][i].second;
if(d[nodcurent]+cost < d[vecin])
{
d[vecin] = d[nodcurent]+cost;
if(!esteincoada[vecin]) coada.push(vecin);
}
}
}
return true;
}
int main(){
in>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,c; in>>x>>y>>c;
graf[x].push_back(make_pair(y,c));
}
if(bellmanford(1))
{
for(int i=2;i<=n;i++) out<<d[i]<<" ";
}
else out<<"Ciclu negativ!";
return 0;
}
Exemplu:
bellmanford.in bellmanford.out
5 8 -5 -3 4 7
1 3 -3
1 5 7
3 2 -2
3 4 7
5 1 4
5 2 3
5 3 4
4 5 3
Vom elabora o librărie în care vom include toate subprogramele de care avem nevoie
pentru a obține soluția problemei labirintului. Ca rezultat final am elaborat librăria cu numele
Bellman_Ford.h
#ifndef BELLMAN_FORD_H_INCLUDED
#define BELLMAN_FORD_H_INCLUDED
using namespace std;
void BellmanFord(int graph[][3], int V, int E, int src){
// Inițializează distanța tuturor vârfurilor ca 0.
int dis[V];
for (int i = 0; i < V; i++)
dis[i] = INT_MAX;
// inițializează distanța sursei ca 0
dis[src] = 0;
18
for (int i = 0; i < V - 1; i++) {
for (int j = 0; j < E; j++) {
if (dis[graph[j][0]] + graph[j][2] <
dis[graph[j][1]])
dis[graph[j][1]] =
dis[graph[j][0]] + graph[j][2];
}
}
for (int i = 0; i < E; i++) {
int x = graph[i][0];
int y = graph[i][1];
int weight = graph[i][2];
if (dis[x] != INT_MAX &&
dis[x] + weight < dis[y])
cout << "Graph contains negative"
" weight cycle"
<< endl;
}
cout << " Distanța vertexului de la sursă: " << endl;
for (int i = 0; i < V; i++)
cout << i << "\t" << dis[i] << endl;
}
#endif // BELLMAN_FORD_H_INCLUDED
Vom elabora un program ce va aplica această librărie pentru a obține soluția problemei
labirintului. Ca rezultat final am elaborat programul Bellman_Ford.cpp
#include <iostream>
#include "BELLMAN_FORD.h"
using namespace std;
int main(){
int V = 5; // Numărul de vârfuri în graph
int E = 8; // Numărul de muchii in graph
/* Fiecare muchie are trei valori (u, v, w) când marginea este de la
vertexul u la v. Și greutatea marginii este w. */
int graph[][3] = { { 0, 1, -1 }, { 0, 2, 4 },
{ 1, 2, 3 }, { 1, 3, 2 },
{ 1, 4, 2 }, { 3, 2, 5 },
{ 3, 1, 1 }, { 4, 3, -3 } };
BellmanFord(graph, V, E, 0);
return 0;
}
19
5. Implementarea algoritmului Bellman-Ford în Matlab.
Exemplul 1 - Găsirea tuturor căilor cele mai scurte într-un graph direcționat.
Rezolvare:
1. Creați și vizualizați un grafic direcționat cu 6 noduri și 11 muchii.
2. Găsiți toate cele mai scurte căi între fiecare pereche de noduri în graph-ul direcționat.
Funcția în Matlab:
function [ output_args ] = Untitled6( input_args )
W = [.41 .99 .51 .32 .15 .45 .38 .32 .36 .29 .21];
DG = sparse([6 1 2 2 3 4 4 5 5 6 1],[2 6 3 5 4 1 6 3 4 3 5],W)
h = view(biograph(DG,[],'ShowWeights','on'))
[dist,path,pred] = graphshortestpath(DG,1,6)
set(h.Nodes(path),'Color',[1 0.4 0.4])
edges = getedgesbynodeid(h,get(h.Nodes(path),'ID'));
set(edges,'LineColor',[1 0 0])
set(edges,'LineWidth',1.5)
end
Soluția
Exemplul 2 - Găsirea tuturor căilor cele mai scurte într-un graph nedirecționat.
Rezolvare:
1. Creați și vizualizați un grafic nedirecționat cu 6 noduri și 11 muchii.
2. Găsiți toate cele mai scurte căi între fiecare pereche de noduri în graph-ul nedirecționat.
Funcția în Matlab:
function [ output_args ] = Untitled6( input_args )
%UNTITLED6 Summary of this function goes here
% Detailed explanation goes here
W = [.41 .99 .51 .32 .15 .45 .38 .32 .36 .29 .21];
DG = sparse([6 1 2 2 3 4 4 5 5 6 1],[2 6 3 5 4 1 6 3 4 3 5],W)
UG = tril(DG + DG')
h = view(biograph(UG,[],'ShowArrows','off','ShowWeights','on'))
[dist,path,pred] = graphshortestpath(UG,1,6,'directed',false)
set(h.Nodes(path),'Color',[1 0.4 0.4])
fowEdges = getedgesbynodeid(h,get(h.Nodes(path),'ID'));
revEdges = getedgesbynodeid(h,get(h.Nodes(fliplr(path)),'ID'));
edges = [fowEdges;revEdges];
set(edges,'LineColor',[1 0 0])
set(edges,'LineWidth',1.5)
end
20
Soluția
Marcarea nodurilor și a marginile pentru celei mai scurte trasee prin colorarea roșie și
îngroșarea liniei.
Exemplul 1 Exemplul 2
Graph direcționat Graph nedirecționat
21
Concluzii
22
Bibliografie
Capitolul 1
1. Kleinberg, Jon; Tardos, Éva (2006). Algorithm Design. New York: Pearson Education,
Inc.
2. Johnson, D.B. (1977). Efficient algorithms for shortest paths in sparse networks. Journal
of the ACM 24(1), 1-13.
3. Siek, J.G., Lee, L-Q, and Lumsdaine, A. (2002). The Boost Graph Library User Guide
and Reference Manual, (Upper Saddle River, NJ:Pearson Education).
4. KOLÁŘ, Josef. Teoretická informatika. 2. ed. Praha : Česká informatická společnost,
2004. 205 p. ISBN 80-900853-8-5.
5. Moore, Edward F. (1959). The shortest path through a maze. Proc. Internat. Sympos.
Switching Theory 1957, Part II. Cambridge, Massachusetts: Harvard Univ. Press.
pp. 285–292. MR 0114710.
Capitolul 2
23