Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теория алгоритмов.doc
Скачиваний:
7
Добавлен:
29.08.2019
Размер:
1.49 Mб
Скачать

Порівняльний аналіз дії алгоритмів на тестовому прикладі

На малюнку показаний вихідний граф з позначеними ребрами(ліворуч) і його остовне дерево мінімальної вартості(праворуч).

Проілюструємо процес вирішення завдання за допомогою алгоритму Прима:

Послідовність вирішення завдання за допомогою алгоритму Крускала:

Тут ребра вартістю 1, 2, 3 і 4 розглянуті першими й усі включені в P, оскільки їхнє додавання не приводить до циклів. Ребра (1, 4) і (3, 4) вартістю 5 не можна включити в P, тому що вони з'єднують вершини одного й того ж компонента й тому замикають цикл. Але ребро, що залишилося (2, 3) також вартості 5 не створює цикл. Після включення цього ребра в P формування остовного дерева завершується.

Час виконання алгоритму Прима має порядок О(п2), де п — кількість вершин у даному графі(дивитеся пункт «Програмна реалізація алгоритмів»). Якщо значення п досить велике, то використання цього алгоритму не раціонально. Алгоритм Крускала виконується за час порядку О(е log2e), де е — кількість ребер у даному графі. Якщо е значно менше n2, то алгоритм Крускала переважніше, але якщо е близько до n2, рекомендується застосовувати алгоритм Прима.

Програмна реалізація алгоритмів

Алгоритм Прима

Якщо ввести два масиви, то можна порівняно просто організувати на кожному кроці алгоритму вибір ребра з найменшою вартістю, що з'єднує множини U і V\U. Масив CLOSEST[i] для кожної вершини i з множини V\U містить вершину з U, з якої він з'єднаний ребром мінімальної вартості (це ребро вибирається серед ребер, інцедентних вершині i, і які ведуть у множину U). Інший масив LOWCOST[i] зберігає значення вартості ребра (i, CLOSEST[i]).

На кожному кроці алгоритму проглядається масив LOWCOST, знаходимо мінімальне значення LOWCOST[k]. Вершина k множині V\U і з'єднана ребром з вершиною з множини U. Потім друкуємо ребро (k, CLOSEST[k]). Тому що вершина k приєднується до множини U, те внаслідок цього змінюються масиви LOWCOST і CLOSEST.

Після знаходження чергової вершини k остовного дерева LOWCOST[k] покладемо рівним infinity (нескінченність), дуже великому числу, такому, щоб ця вершина надалі не розглядалася. Значення числа infinity повинне бути більше вартості будь-якого ребра графа.

На вхід програми надходить масив З розміру n n, чиї елементи C[i, j] рівні вартості ребер (i, j). Якщо ребра (i, j) не існують, то елемент C[i, j] покладається рівним деякому досить великому числу.

Фрагмент програми мовою Паскаль, що реалізує алгоритм Прима:

procedure Prim ( З: array[l..n, l..n] of integer );

{ Prim друкує ребра остовного дерева мінімальної вартості графа з вершинами {1, ..., n} і матрицею вартості З}

var

LOWCOST: array[l..n] of integer;

CLOSEST: array[l..n] of integer;

i,j,k,min:integer;

{ i і j - індекси. При перегляді масиву LOWCOST, k - номер знайденої вершини, min = LONCOST[k] }

begin

{1} for i:= 2 to n do begin

{ спочатку в U тільки вершина 1 }

{2} LOWCOST[i]:= C[l,i];

CLOSEST[i]:=1;

{3} end;

{4} for i:= 2 to n do begin

{ пошук поза U найкращої вершини k, що має інцедентне ребро, що кінчається в U}

{5} min:= LOWCOST[2] ;

{6} k:= 2;

{7} for j:= 3 to n do

{8} if LOWCOST[j] < min then begin

{9} min: = LOWCOST[j] ;

{10}k:= j

end;

{11} writeln(k, CLOSEST[k]); { друк ребра }

{12} LOWCOST[k]:= infinity; (k додається в U )

{13} for j:= 2 to n do {коректування вартостей в U }

{14} if (C[k, j] < LOWCOST[j]) and (LOWCOST[j] < infinity) then begin {15}LOWCOST[j]:= C[k, j];

{16}CLOSEST[j]:= k

end

end

end;

Час виконання алгоритму має порядок О(п2), оскільки виконується п-1 ітерація зовнішнього циклу рядків (4) -(16), а кожна ітерація цього циклу вимагає часу порядку О(п) для виконання внутрішніх циклів у рядках (7) -(10) і (13) -(16).

Алгоритм Крускала

Його програмна реалізація близько відповідає відповідній алгоритму-схемі й опису, наведеному в розділі «Алгоритм Крускала», але щоб уникнути повторення ідентифікаторів перепозначимо в програмі ребро (і, v) на (в, v), і, отже, вектор Mark[u] на Mark[v].

Програма, що реалізує алгоритм:

Program Cruscal;

Uses wincrt;

Const

nVer=50; {Максимальна кількість вершин}

nRib=1000; (Максимальна кількість ребер}

Турі

Vertex=array[1..nVer] of Integer;

Rib=array[1..nRib] of Integer;

Var

n :Integer; { Кількість вершин у графі }

n:Integer; { Кількість ребер у графі }

Mark :Ver; { Мітки приналежності вершин }

U:Ver; { Список вершин графа }

E:Rib; { Реберний список графа }

nEo:Integer; { Кількість ребер в остовному дереві}

Eo:Rib; { Ребра остовного дерева }

We:Rib; { Ваги ребер графа }

i,j:integer;

f:text;

Procedure Init; { Перепризначення міток вершин }

Var

i,j,m :Integer;

begin

for i:=l to 2*n do Eo[i]:=l;

for i:=l to 2*n do

for j:=i+l to 2*n do

if Eo[j]=l then

if E[j]=E[i] then Eo[j]:=0;

n:=0;

for i:=l to 2*n do

if Eo[i]=l then begin

n:=n+l;

U[n]:=E[i];

end;

for i:=l to 2*n do {Нові мітки}

for m:=l to n do

if E[i]=U[m] then begin E[i]:=m; break;

end;

end;

Procedure Sort; { Сортування списку ребер no їхнім вагам }

var

i,j,k :Integer;

w:Integer;

begin

for i:=l to n do

for j:=l to nE-i do

if We[j]>We[j+l] then begin

w:=We[j];

We[j]:=We[j+1] ;

We[j+l]:=w;

w:=E[2*j-l] ;

E[2*j-l]:=E[2*(j +1)-1];

E[2*(j+1)-1]:=w;

w:=E[2*j];

E[2*j]:=E[2*(j+1)];

E[2*( j+1)]:=w;

end;

end;

Procedure Ostov; { Будуємо мінімальне остовне дерево }

Var

i,y,v,z :Integer;

s:Integer;

begin

for i:=l to n do Mark[i]:=i;

Sort; {Сортування ребер по вазі}

nEo:=0; {Порожня б Eo}

s:=l; {Початкове ребро в сортованій E}

while nEo<nU-l do begin

y:=E[2*s]; {Вибір нового ребра зі списку}

v:=E[2*sE-l] ;

if Mark[y]<>Mark [v] then begin

nEo:=nEo+l;

z:=Mark[y]; {Злиття}

for i:=l to n do

if Mark[i]=z then

Mark[i] :=Mark[y] ;

Write(U[y],', ');

Write(U[v]);

writeln;

end;

s:=s+l; {Видалити ребро (y,v) зі списку E}

end;

end;

begin

Assign(f,'з:/graf.txt');

Reset (f) ; {Файл відкритий для читання}

Read(f,n); {Кількість ребер у реберному списку графа}

for i:=l to n do Read (f ,E[2*i-l] ) ; { Перші вершини ребер }

for i:=l to n do Read (f , E [2*i] ) ; { Другі вершини ребер}

for i:=l to n do Read (f , We [i] ) ; { Ваги ребер }

Close (f) ;

Init;

Sort;

Writeln('Min ostov:');

Ostov;

end.

Для програми цього алгоритму вихідні дані графа на задаються реберним списком у текстовому файлі graf.txt з наступною структурою:

  • у першому рядку файлу записується кількість ребер у списку;

  • у другому й третьому рядках вказуються ребра своїми вершинами: одна вершина в другому рядку, інша вершина ребра в третьому рядку;

  • у четвертому рядку розташовуються значення ваг відповідних ребер.

Алгоритм Крускала виконується за час порядку О(е log2e), де е — кількість ребер у даному графі.