Представление графов и отношений Граф G = (V,R), V – множество вершин, R – множество ребер 1) неориентированные графы 2) ориентированные, или орграфы, 3) взвешенные неориентированные графы 4) взвешенные ориентированные графы 5) мультиграфы 1 3 2 4 5 6 7 (1,2) (3,1) (2,3) (4,3) (5,6) 1 2 3 4 5 6 7 1 1 1 1 2 1 3 1 1 1 4 1 1 5 6 1 7 2 1 1 3 6 5 3 3 2 4 Формирование списков, задающих граф Вершины графа – номера от 1 до n. Число ребер - m. Ребро графа – два номера вершин (p,q). i-е ребро – (v1[i],v2[i]). ________________________________________ for k:=1 to n do S[k]:=nil; {обнуление указателей} for i:=1 to m do {формирование списков} begin new(ps); ps^.s:=v2[i]; k:=v1[i]; ps^.p:=S[k]; S[k]:=ps; {формирование 2-го элемента для неор.графа:} new(ps); ps^.s:=v1[i]; k:=v2[i]; ps^.p:=S[k]; S[k]:=ps end; Представление графа массивом смежных вершин 1 3 2 4 5 6 7 1 2 3 4 5 6 7 8 9 10 L S D 2 3 1 3 1 2 4 3 6 5 2 2 3 1 1 1 0 1 3 5 8 9 10 11 Формирование массивов D, S и L для задания неориентированного графа for j:=1 to n do L[j]:=0;{обнуление длин списков} for i:=1 to m do begin {вычисление длин списков} k:=v1[i]; L[k]:=L[k]+1; k:=v2[i]; L[k]:=L[k]+1; end; S[1]:=1; {вычисление указателей на начала списков в массиве D} for j:=2 to n do S[j]:=S[j-1]+L[j-1]; for j:=1 to n do {дублирование указателей} U[j]:=S[j]; for i:=1 to m do {распределение смежных вершин} begin {по спискам массива D} k:=v1[i]; D[U[k]]:=v2[i]; U[k]:=U[k]+1 k:=v2[i]; D[U[k]]:=v1[i]; U[k]:=U[k]+1 end; Просмотр неориентированного графа вглубь Массив R для нумерации вершин графа по порядку просмотра. Если i–я вершина при просмотре была j–й, то R[i]=j. ______________________________________________________________________ procedure deеp(k:integer); var i: integer; begin for i:=1 to n do if (M[k,i]=1)and(R[i]=0) then begin nom:=nom+1; R[i]:=nom; deеp(i) end end; ______________________________________________________________________ for i:=1 to n do R[i]:=0; R[a]:=1; nom:=1; deеp(a); {просмотр, начиная с вершины номер a} Выделение компонент связности графа for i:=1 to n do C[i]:=0; 1 q:=0; L S D 2 for i:=1 to n do 2 1 if C[i]=0 then begin 2 3 3 5 q:=q+1; C[i]:=q; 1 8 cdeеp(i) 1 9 end; 1 10 0 11 ________________________ procedure cdeеp(k:integer); var i: integer; begin for i:=S[k] to S[k]+L[k]-1 do begin j:=D[i]; if C[j]=0 then begin C[j]:=q; cdeеp(j) end end end; 2 3 4 5 6 7 8 9 10 3 1 3 1 2 4 3 6 5 Просмотр неориентированного графа вширь для массива смежных вершин V - уровни просмотренных вершин P – номера просмотренных вершин (очередь) __________________________________________ P[1]:=1; r:=1; t:=1; {очередь из одной вершины} for i:=1 to n do V[i]:=0; V[1]:=1; {уровень для первой вершины} while t<=r do begin k:=P[t]; q:=V[k]+1; for i:=S[k] to S[k]+L[k]-1 do begin j:=D[i]; if V[j]=0 then begin V[j]:=q; r:=r+1; P[r]:=j end end; t:=t+1 end; Просмотр неориентированного графа вширь для матрицы смежности V - уровни просмотренных вершин P – номера просмотренных вершин (очередь) __________________________________________ P[1]:=1; r:=1; t:=1; {очередь из одной вершины} for i:=1 to n do V[i]:=0; V[1]:=1; {уровень для первой вершины} while t<=r do begin k:=P[t]; q:=V[k]+1; for i:= 1 to n do if (M[k,i]=1)and(V[i]=0) then begin V[i]:=q; r:=r+1; P[r]:=i end end; t:=t+1 end; Поиск кратчайшего пути в лабиринте Н # # # # # # # # # # К # # # # # 1 # # 2 # # # 3 4 5 # 4 5 # 5 # # # # # # # # # 11 # # 9 10 # 6 7 8 9 # # # 8 # 10 # 6 # 10 9 10 11 # # # # # # # # Pi[1]:=i0; Pj[1]:=j0; r:=1; t:=1; L[i0,j0]:=1; while t<=r do begin i:=Pi[t]; j:=Pj[t]; q:=L[i,j]+1; if L[i-1,j]=0 then begin L[i-1,j]:=q; r:=r+1; Pi[r]:=i-1; Pj[r]:=j end; if L[i,j-1]=0 then begin L[i,j-1]:=q; r:=r+1; Pi[r]:=i; Pj[r]:=j-1 end; if L[i+1,j]=0 then begin L[i+1,j]:=q; r:=r+1; Pi[r]:=i+1; Pj[r]:=j end; if L[i,j+1]=0 then begin L[i,j+1]:=q; r:=r+1; Pi[r]:=i; Pj[r]:=j+1 end; t:=t+1 end; Отслеживание кратчайшего пути в лабиринте k:=L[ik,jk]; i:=ik; j:=jk; while k>0 do begin Mi[k]:=i; Mj[k]:=j; if L[i-1,j]<L[i,j] then i:=i-1 else if L[i,j-1]<L[i,j] then j:=j-1 else if L[i+1,j]<L[i,j] then i:=i+1 else j:=j+1; k:=k-1 end; Поиск кратчайшего пути в лабиринте алгоритмом бэктрекинга procedure Lab(i,j,k:integer); begin if (i=ik)and(j=jk) then begin kmin:=k; {ЗАПОМНИТЬ МАРШРУТ} end else if k<kmin then begin if L[i-1,j]=0 then begin L[i-1,j]:=1; Pi[k]:=i-1; Pj[k]:=j; Lab(i-1,j,k+1); L[i-1,j]:=0 end; if L[i,j-1]=0 then begin . . . end; if L[i+1,j]=0 then begin . . . end; if L[i,j+1]=0 then begin . . . end end end; Вызов процедуры поиска кратчайшего пути в лабиринте kmin:={∞}; L[i0,j0]:=1; Pi[1]:=i0; Pj[1]:=j0; Lab(i0,j0,2); Трудоемкость: T (k) ≤ 3 + 32 + 33 + . . . + 3k = 3(3k – 1)/2, где k – длина пути, k < n2. Эйлеров цикл Количество ребер, входящих во все вершины (для орграфа): for i:=1 to n do R[i]:=0; for i:=1 to n do for k:=S[i] to S[i]+L[i]-1 do begin j:=D[k]; R[j]:=R[j]+1 end Проверка существования эйлерова цикла (для орграфа) : p:=1; for i:=1 to n do if R[i]<>L[i] then p:=0; if p=1 then СУЩЕСТВУЕТ else НЕ СУЩЕСТВУЕТ; Эйлеров цикл Вставка побочного цикла в основной цикл: 1 pb i k i1 i i k p 1 pb 1 p 1 Вычисление эйлерова цикла в орграфе для массива смежных вершин new(p); pb:=p; p^.s:=1; p^.p:=nil; while p<>nil do begin if L[p^.s]>0 then begin p1:=p^.p; i0:=p^.s; i:=0; p0:=p; while i<>i0 do begin new(p2); p^.p:=p2; i:=p^.s; i1:=D[S[i]]; S[i]:=S[i]+1; L[i]:=L[i]-1; i:=i1; p2^.s:=i; p:=p2 end; p^.p:=p1; p:=p0 end else p:=p^.p end; Существование эйлерова цикла в орграфе для матрицы смежности количество ребер, выходящих из всех вершин: for i:=1 to n do begin L[i]:=0; for j:=1 to n do if M[i,j]=1 then L[i]:=L[i]+1 end; количество ребер, входящих во все вершины: for j:=1 to n do begin R[j]:=0; for i:=1 to n do if M[i,j]=1 then R[j]:=R[j]+1 end; Проверка существования эйлерова цикла: p:=1; for i:=1 to n do if R[i]<>L[i] then p:=0; if p=1 then СУЩЕСТВУЕТ else НЕ СУЩЕСТВУЕТ; Вычисление эйлерова пути в орграфе 1. Вычисление количества ребер, входящих в вершины. 2. Нахождение вершины ib – начала пути, и вершины ik – конца пути. 3. Построение какого-либо пути из вершины ib в вершину ik. После этого во всех вершинах останется по одинаковому числу исходящих и входящих дуг. 4. Построение полного пути добавлением боковых циклов. Вычисление начального пути в орграфе new(p); pb:=p; p^.s:=ib; i:=ib; while L[i]>0 do begin new(p1); p^.p:=p1; i1:=D[S[i]]; S[i]:=S[i]+1; L[i]:=L[i]-1; p1^.s:=i1; p:=p1; i:=i1 end; p^.p:=nil; Существование эйлерова цикла в неориентированном графе для матрицы смежности количество ребер, смежных со всеми вершинами: for i:=1 to n do begin L[i]:=0; for j:=1 to n do if M[i,j]=1 then L[i]:=L[i]+1 end; Проверка существования эйлерова цикла: p:=1; for i:=1 to n do if odd(L[i]) then p:=0; if p=1 then СУЩЕСТВУЕТ else НЕ СУЩЕСТВУЕТ; Вычисление эйлерова цикла в неориентированном графе для матрицы смежности new(p); pb:=p; p^.s:=1; p^.p:=nil; for i:=1 to n do U[i]:=1; while p<>nil do begin j:=p^.s; k:=U[j]; while (k<=n)and(M[j,k]=0) do k:=k+1; U[j]:=k; if k<=n then begin p1:=p^.p; i0:=p^.s; i:=0; p0:=p; while i<>i0 do begin new(p2); p^.p:=p2; i:=p^.s; k:=U[i]; while (k<=n)and(M[i,k]=0) do k:=k+1; U[i]:=k; M[i,k]:=0; M[k,i]:=0; i:=k; p2^.s:=k; p:=p2 end; p^.p:=p1; p:=p0 end else p:=p^.p end; Вычисление всех возможных гамильтоновых циклов в графе для матрицы смежности procedure hamilton(k:integer); var i,j:integer; begin i:=P[k-1]; for j:=1 to n do if (R[j]=0)and(M[i,j]=1) then begin P[k]:=j; R[j]:=1; if k=n then begin if M[j,1]=1 then ВЫВОД end else hamilton(k+1); R[j]:=0 end end; Вызов: for j:=1 to n do R[j]:=0; P[1]:=1; R[1]:=1; hamilton(2); Вычисление всех возможных гамильтоновых циклов в графе для массива смежных вершин procedure hamilton(k:integer); var i,j,q:integer; begin q:=P[k-1]; for i:=S[q] to S[q]+L[q]-1 do begin j:=D[i]; if R[j]=0 then begin P[k]:=j; R[j]:=1; if k=n then begin {Упорядоченные номера в D} if D[S[j]]=1 then ВЫВОД end else hamilton(k+1); R[j]:=0 end end; Вычисление топологической сортировки Количество ребер, входящих во все вершины: for i:=1 to n do R[i]:=0; for i:=1 to n do for k:=S[i] to S[i]+L[i]-1 do begin j:=D[k]; R[j]:=R[j]+1 end Массив P – очередь вершин, в которые нет входящих дуг: k:=0; t:=1; for i:=1 to n do if R[i]=0 then begin k:=k+1; P[k]:=i end; Вычисление топологической сортировки while t<=k do begin i:=P[t]; for j:=S[i] to S[i]+L[i]-1 do begin q:=D[j]; R[q]:= R[q]-1; if R[q]=0 then begin k:=k+1; P[k]:=q end end; t:=t+1 end; Вычисление обратной перестановки: for i:=1 to n do Q[P[i]]:=i;