Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
19
Добавлен:
08.01.2014
Размер:
129.54 Кб
Скачать

Краткие теоретические основы

Кратчайший остов (SST) графа

Рассмотрим взвешенный связный неориентированный граф G = (X, А), вес ребра (xi, xj) обозначим cij. Из большого числа остовов графа нужно найти один, у которого сумма весов ребер наименьшая. Такая задача возникает, например, в том случае, когда вершины являются клеммами электрической сети, которые должны быть соединены друг с другом с помощью проводов наименьшей общей длины (для уменьшения уровня наводок).

Другой пример: вершины представляют города, которые нужно связать сетью трубопроводов; тогда наименьшая общая длина труб, которая должна быть использована для строительства (при условии, что вне городов «разветвления» трубопроводов не допускаются), определяется кратчайшим остовом соответствующего графа.

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

Этот алгоритм порождает SST посредством разрастания только одного поддерева, например Ts, содержащего больше одной вершины. «Одиночные» вершины рассматриваются как отдельные поддеревья. Поддерево Ts постепенно разрастается за счет при­соединения ребер (xi, xj), где xiTs и xjTs; причем добавляемое ребро должно иметь наименьший вес cij. Процесс продолжается до тех пор, пока число ребер в Ts не станет равным n-1. Тогда поддерево Ts будет требуемым SST.

Алгоритм начинает работу с присвоения каждой вершине xjTs, пометки [j, j], где j, на каждом шаге есть ближайшая к xj вершина из поддерева Ts, а j — вес ребра (j, xj). На каждом шаге выполнения алгоритма вершина, например xj*, с наименьшей пометкой j присоединяется к Ts посредством добавления ребра (j*, xj*). Поскольку к Ts добавлена новая вершина xj*, то, может быть, придется изменить пометки [j, j] у некоторых вершин xjTs, (если, например, с(xj, xj*) меньше существующей пометки j) и после этого продолжить процесс.

Описание алгоритма:

Шаг 1. Пусть Ts = {x1}, где x1 первая вершина, и As =  (As, является множеством ребер, входящих в SST).

Шаг 2. Для каждой вершины xjTs найти вершину jTs, такую, что

и приписать вершине xj пометку [j, j]. Если такой вершины j, нет, приписать вершине xj пометку [0, ].

Шаг 3. Выбрать такую вершину xj*, что

Обновить данные: Ts = Ts U {xj*}. As = As U {(j*, xj*)}. Если |Ts| = n, то остановиться. Ребра в As образуют SST. Если |Ts|  n, то перейти к шагу 4.

Шаг 4. Для всех xjTs, таких, что xjГ(xj*), обновить пометки следующим образом:

Если j > с (xj*, xj), то положить j = с (xj*, xj),j = xj* и вернуться к шагу 3.

Если j  с (xj*, xj), то перейти к шагу 3.

Блок-схема алгоритма

Инструкция по пользованию программой

Программа “Prim” используется для нахождения кратчайшего остова графа.

1. Начало работы с программой

Первое, что необходимо сделать – это задать количество вершин графа в соответствующем окне.

2. Заполнение матрицы

После нажатия кнопки “OK” на экране появится матрица нужного размера. Матрица является матрицей весов ребер графа. В ячейках матрицы задаются веса ребер, начало которых – номер строки, а конец – номер столбца. Если такого пути не существует, то в ячейке ставится «0». При задании мульти-графа веса параллельных ребер задаются через знак «-». Пример: 3-2-10.

Необходимо заполнить только ту половину матрицы, которая выше главной диагонали. Остальное сделает программа.

Внимание: матрица должна быть целиком заполнена!

4. Нахождение минимального остова графа

Для нахождения минимального остова графа надо нажать кнопку «Выполнить». После нажатия этой кнопки программа произведет необходимые вычисления в соответствии с прилагаемым алгоритмом и выведет результат в окно справа от матрицы. Результат выводится в виде:

Ts: As:

x1

x5 x1;3

x2 x5;3

x3 x2;3

x4 x5;3

,где Ts – вершина-источник, As – вершина-сток и вес ребра.

5. Дополнительные возможности

В меню «Файл» Вы можете распечатать результат, настроить принтер, сохранить результат в файл (в формате RichText) и выйти из программы. В меню «Редактирование» Вы можете изменить текущий шрифт.

Текст программы

unit prim1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, Buttons, Grids, ComCtrls, Menus;

type

TForm1 = class(TForm)

Grid1: TStringGrid;

Edit1: TEdit;

Label1: TLabel;

BitBtn1: TBitBtn;

BitBtn2: TBitBtn;

Memo1: TMemo;

Label2: TLabel;

Label3: TLabel;

RichEdit1: TRichEdit;

MainMenu1: TMainMenu;

N1: TMenuItem;

N2: TMenuItem;

N3: TMenuItem;

N4: TMenuItem;

N5: TMenuItem;

PrintDialog1: TPrintDialog;

PrinterSetupDialog1: TPrinterSetupDialog;

FontDialog1: TFontDialog;

N6: TMenuItem;

N7: TMenuItem;

N8: TMenuItem;

SaveDialog1: TSaveDialog;

procedure BitBtn1Click(Sender: TObject);

procedure BitBtn2Click(Sender: TObject);

procedure Grid1SetEditText(Sender: TObject; ACol, ARow: Integer;

const Value: String);

procedure N5Click(Sender: TObject);

procedure N2Click(Sender: TObject);

procedure N3Click(Sender: TObject);

procedure N7Click(Sender: TObject);

procedure N8Click(Sender: TObject);

Function Multi(col,row:integer):integer;

private

{ Private declarations }

public

{ Public declarations }

end;

var

n:integer;

Form1: TForm1;

implementation

{$R *.DFM}

Function TForm1.Multi(col,row:integer):integer;

var str,temp:string;

ax:array of integer;

count,cx,bx,min:integer;

begin

str:=Grid1.Cells[col,row];

count:=0;

For cx:=1 to Length(str) do

begin

if str[cx]='-' then count:=count+1;

end;

if count=0 then SetLength(ax,1)

else SetLength(ax,count+1);

bx:=0;

For cx:=1 to Length(str) do

begin

if str[cx]<>'-' then temp:=temp+str[cx]

else

begin

ax[bx]:=StrToInt(temp);

bx:=bx+1;

temp:='';

end;

if cx=Length(str) then

begin

ax[bx]:=StrToInt(temp);

{ break;}

end;

end;

min:=10000;

For cx:=0 to count+1 do

begin

if ax[cx]<min then

begin

min:=ax[cx];

bx:=cx;

end;

end;

Multi:=min;

end;

{Процедура на нажатие кнопки "ОК"}

procedure TForm1.BitBtn1Click(Sender: TObject);

var ax,cx:integer;

begin

{Создание сетки нужного размера}

n:=StrToInt(Edit1.Text);

Grid1.ColCount:=n+1;

Grid1.RowCount:=n+1;

For ax:=1 to n do

Grid1.Cols[ax].Strings[0]:=IntToStr(ax);

For ax:=1 to n do

Grid1.Cols[0].Strings[ax]:=IntToStr(ax);

{Кнопку "Выполнить" делаем видимой}

BitBtn2.Enabled:=True;

end;

{Процедура на нажатие кнопки "Выполнить"}

procedure TForm1.BitBtn2Click(Sender: TObject);

var

cost:array of integer;

dest:array of integer;

ax,y,min,bx,z,cx:integer;

str:string;

{cost-массив весов; dest-массив вершин-стоков}

begin

For ax:=1 to n do

For cx:=1 to n do

if cx=ax then Grid1.Cells[ax,cx]:='0';

RichEdit1.Lines.Clear;

RichEdit1.Lines.Add('Исходный граф:');

RichEdit1.Lines.Add('');

For ax:=1 to n do

begin

str:=Grid1.Cells[ax,1];

For cx:=2 to n do

begin

str:=str+' ';

str:=str+Grid1.Cells[ax,cx]

end;

RichEdit1.Lines.Add(str);

end;

RichEdit1.Lines.Add('');

RichEdit1.Lines.Add('');

RichEdit1.Lines.Add('');

RichEdit1.Lines.Add('Минимальный остов графа:');

{Memo1 используется для вывода на экран результатов}

Memo1.Clear;

Memo1.Lines.Add('Ts: As:');

RichEdit1.Lines.Add('Ts: As:');

Memo1.Lines.Add('x1');

RichEdit1.Lines.Add('x1');

SetLength(cost,n+1);

SetLength(dest,n+1);

{Заносим в массивы начальные значения}

{------------- Шаг1 -------------}

For ax:=1 to n do

cost[ax]:=Multi(ax,1);

min:=100000;

For ax:=1 to n do

dest[ax]:=1;

{Нахождение ребра с минимальным весом}

{------------- Шаг2 -------------}

For ax:=2 to n do

if (cost[ax]>0) and (cost[ax]<min) then

begin

min:=cost[ax];

y:=ax;

end;

{Вывод на экран}

Memo1.Lines.Add('x'+IntToStr(y)+' x'+IntToStr(dest[y])+';'+IntToStr(cost[y]));

RichEdit1.Lines.Add('x'+IntToStr(y)+' x'+IntToStr(dest[y])+';'+IntToStr(cost[y]));

{Обновляем данные}

{------------- Шаг3 -------------}

For ax:=1 to n do

Grid1.Cells[1,ax]:=IntToStr(0);

For ax:=1 to n do

Grid1.Cells[y,ax]:=IntToStr(0);

cost[y]:=0;

bx:=2;

Repeat

{------------- Шаг4 -------------}

For ax:=2 to n do

if (Multi(ax,y)<>0) and ((cost[ax]=0) or (cost[ax]>Multi(ax,y))) then

begin

cost[ax]:=Multi(ax,y);

dest[ax]:=y;

end;

min:=100000;

{Нахождение ребра с минимальным весом}

For ax:=2 to n do

if (cost[ax]>0) and (cost[ax]<min) then

begin

min:=cost[ax];

z:=ax;

end;

{Вывод на экран}

Memo1.Lines.Add('x'+IntToStr(z)+' x'+IntToStr(dest[z])+';'+IntToStr(cost[z]));

RichEdit1.Lines.Add('x'+IntToStr(z)+' x'+IntToStr(dest[z])+';'+IntToStr(cost[z]));

{Обновляем данные}

For ax:=1 to n do

Grid1.Cells[z,ax]:=IntToStr(0);

cost[z]:=0;

y:=z;

bx:=bx+1;

Until bx=n;

end;

procedure TForm1.Grid1SetEditText(Sender: TObject; ACol, ARow: Integer;

const Value: String);

begin

Grid1.Cells[ARow,Acol]:=Grid1.Cells[Acol,Arow];

end;

procedure TForm1.N5Click(Sender: TObject);

begin

Application.Terminate;

end;

procedure TForm1.N2Click(Sender: TObject);

begin

if PrintDialog1.Execute then

RichEdit1.Print('Алгоритм Прима');

end;

procedure TForm1.N3Click(Sender: TObject);

begin

PrinterSetupDialog1.Execute;

end;

procedure TForm1.N7Click(Sender: TObject);

begin

FontDialog1.Font:=Memo1.Font;

if FontDialog1.Execute then begin

Memo1.Font:=FontDialog1.Font;

RichEdit1.Font:=FontDialog1.Font;

end;

end;

procedure TForm1.N8Click(Sender: TObject);

begin

if SaveDialog1.Execute then

RichEdit1.Lines.SaveToFile(SaveDialog1.FileName);

end;

end.

Список литературы

Н.Кристофидос «Теория графов. Алгоритмический подход.»

Соседние файлы в папке Ишова