Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Глава 12.doc
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
322 Кб
Скачать
☆

Interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms,Dialogs, StdCtrls, Grids;

type

TForml = class(TForm)

StringGridl: TStringGrid;

Edit1: TEdit; Edit2: TEdit;

Label1: TLabel; Label2: TLabel;

Label3: TLabel; Label4: TLabel;

Button1: TButton;

procedure FormActivate(Sender: TObject);

procedure ButtonlClickfSender: TObject);

private { Private declarations }

public { Public declarations }

end;

var

Form1: TForm1;

Implementation

{$R *.DFM}

procedure TForml.FormActivate(Sender: TObject);

var i:integer;

begin

// нумерация строк

for i:=1 to 10 do

StringGrid1.Cells[0,i]:=IntToStr(i); // нумерация колонок

for i:=1 to 10 do

StringGrid1.Cells[1,0]:=IntToStr(i);

// описание предопределенной карты

StringGridl.Cells[1,2]:='1'

StringGridl.Cells[2,l]:='1'

StringGridl.Cells[1,3]:='1'

StringGridl.Cells[3,1]:='1'

StringGridl.Cells[1,4]:='1'

StringGridl.Cells[4,1]:='1'

StringGridl.Cells[3,7]:='1'

StringGridl.Cells[7,3]:='1'

StringGridl.Cells[4,6]:='1'

StringGridl.Cells[6,4]:='1'

StringGridl.Cells[5,6]:='1'

StringGridl.Cells[6,5]:='1'

StringGridl.Cells[5,7]:='1'

StringGridl.Cells[7,5]:='1'

StringGridl.Cells[6,7]:='1'

StringGridl.Cells[7,6]:='1'

end;

procedure TForml.ButtonlClick(Sender: TObject);

const

N=10;// кол-во вершин графа

var

map:array[1..N,1..N]of integer;

// Карта.map[i,j]не 0, если точки i и j соединены

road:array[1..N]of integer; // Дорога - номера точек карты

incl:array[1..N]of boolean; // incl[1]равен TRUE, если точка

// с номером i включена в road

start,finish:integer; // Начальная и конечная точки

found:boolean; i,j:integer;

procedure step(s,f,p:integer);

var

с:integer;// Номер точки, в которую делаем очередной шаг

i:integer;

begin

if s=f then begin

// Точки s и f совпали !

found:=TRUE;

Labell.caption:=Labell.caption+#13+'Путь:';

for i:=l to p-1 do

Labell.caption:=Labell.caption+' '+IntToStr(road[i]);

end

else begin

// выбираем очередную точку

for c:=l to N do

begin // проверяем все вершины

if(map[s,c]<> 0)and(NOT incl(c))

// точка соединена с текущей и не включена в маршрут

then begin

road[p]:=c;// добавим вершину в путь

incl[c]:=TRUE;// пометим вершину как включенную

step(c,f,p+l); incl[c]:=FALSE; road[p]:=0;

end;

end;

end;

end;// конец процедуры step

begin

Label1.caption: =' ' ;

// инициализация массивов

for i:=1 to N do road[i]:=0;

for i:=1 to N do incl[i]:=FALSE;

// ввод описания карты из SrtingGrid.Cells

for i:=l to N do

for j:=1 to N do

if StringGrid1.Cells[i,j] <> ''

then map[i,j]:=StrToInt(StringGrid1.Cells[i, j] ;

else map[i,j]:=0;

start:=StrToInt(Editl.text);

finish:=StrToInt(Edit2.text);

road[l]:=start;// внесем точку в маршрут

incl[start]:=TRUE;// пометим ее как включенную

step(start,finish,2);//ищем вторую точку маршрута

// проверим, найден ли хотя бы один путь

if not found

then Labell.caption:='Указанные точки не соединены!';

end;

end.

При запуске программы в момент активизации формы приложения происходит событие onActivate, процедура обработки которого заполняет массив StringGrid1.cells значениями, представляющими описание карты. Этаже процедура нумерует строки и столбцы таблицы, заполняя зафиксированные ячейки первого столбца и первой строки StringGrid1.

Поиск маршрута инициирует процедура TForm1.Button1Click, которая запускается щелчком на кнопке Поиск. Данная процедура для поиска точки, соединенной с исходной точкой, вызывает процедуру step, которая после выбора первой точки, соединенной с начальной, и включения ее в маршрут вызывает сама себя. При этом в качестве начальной точки задается уже не исходная, а текущая, только что включенная в маршрут.

Поиск кратчайшего пути

Обычно задача поиска пути на графе формулируется следующим образом: найти наилучший маршрут. Под наилучшим маршрутом, как правило, понимают кратчайший. Найти кратчайший маршрут можно выбором из всех найденных. Однако совсем не обязательно искать все маршруты.

Можно поступить иначе: во время выбора очередной точки проверить, не превысит ли длина формируемого маршрута длину уже найденного пути, если эта точка будет включена в маршрут; если превысит, то эту точку следует пропустить и выбрать другую.

Таким образом, после того как будет найден первый маршрут, программа будет вести поиск только по тем ветвям графа, которые могут улучшить найденное решение, отсекая пути, делающие формируемый маршрут длиннее уже найденного.

В листинге 12.6 приведена процедура, которая использует процедуру step, выполняющую выбор очередной точки маршрута таким образом, что обеспечивается поиск пути минимальной длины.

Листинг 12.6. Поиск кратчайшего пути

procedure TForm1.ButtonlClick(Sender: TObject);

const

N=10;{ кол-во вершин графа}

var

map:array[1..N,1..N]of integer;

// Карта.map[i,j] не 0,если точки i и j соединены

road:array[1..N]of integer; // Дорога — номера точек карты

incl:array[1..N]of boolean; // incl[1]равен TRUE,если точка

// с номером i включена в road

start, finish:integer; // Начальная и конечная точки

found:boolean;

len:integer; // длина найденного (минимального)маршрута

c_len:integer; // длина текущего (формируемого)маршрута

i,j:integer; // выбор очередной точки

procedure step(s,f,p:integer);

var

с:integer; { Номер точки, в которую делаем очередной шаг }

i:integer;

begin

if s=f then begin

len:=c_len;{ сохраним длину найденного маршрута }

{ вывод найденного маршрута }

for i:=1 to p-1 do

Label1.caption:=Label1.caption+' '+IntToStr(road[i]);

Label1.caption:=Label1.caption +', длина:'+IntToStr(len)+#13;

end

else { выбираем очередную точку }

for c:=l to N do { проверяем все вершины }

if(map[s,c]<> 0)and(NOT incl[c])

and((len=0)or(c_len+map[s,c]< len)) then begin

// точка соединена с текущей, но не включена в маршрут

road[p]:=c;{ добавим вершину в путь }

incl[c]:=TRUE;{ пометим вершину как включенную }

c_len:=c_len+map[s,с];

step(c,f,p+l);

incl[c]:=FALSE; road[p]:=0;

c_len:=c_len-map[s,с];

end;

end; { конец процедуры step }

begin

Labell.caption:='';

{ инициализация массивов }

for i: =1 to N do road [ i ]:=0;

for i:=l to N do incl[i]:=FALSE;

{ ввод описания карты из SrtingGrid.Cells}

for i:=l to N do

for j:=1 to N do

if StringGrid1.Cells[i, j] <> "

then map[i,j]:=StrToInt(StringGridl.Cells[i,j])

else map[i,j]:=0;

len:=0; // длина найденного (минимального) маршрута

c_len:=0; // длина текущего (формируемого) маршрута

start:=StrToInt(Edit1.text);

finish:=StrToInt(Edit2.text);

road[1]:=start;{ внесем точку в маршрут }

incl[start]:=TRUE;{ пометим ее как включенную }

step(start,finish,2);{ищем вторую точку маршрута }

// проверим, найден ли хотя бы один путь

if not found

then Label1.caption:='Указанные точки не соединены!';

end;

Диалоговое окно программы поиска кратчайшего пути и процедура обработки события OnActivate ничем не отличаются от диалогового окна и соответствующей процедуры OnActivate программы поиска всех возможных маршрутов, рассмотренной в предыдущем разделе.