Главная » Курсовые

Фибоначчиевы кучи

Введение

Существует много задач, где применяется работа с графами. При такой работе более целесообразно использовать фибоначиевы кучи.

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

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

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

Объект данной курсовой- фибоначчиевы кучи.

 

Цель- научиться работать с  фибоначчиевыми кучами.

 

Задачи:

  1. Изучить теорию по теме фибоначиевы кучи.
  2. Научиться на практике применять полученные знания.
  3. Создать программу, использующую, алгоритм Дейкстры

Актуальность: алгоритм Дейкстры очень сложен для ручного расчета, поэтому его реализация очень актуальна.

 

Глава I. Фибоначчиевы кучи

1.1. Двоичные кучи

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

 

Структура "Двочная куча" (Binary Heap) позволяет хранить пары ключ-значение (key-value), и быстро выполнять операцию извлечения пары с минимальным значением ключа и операцию добавления новых пар.

С помощью двоичной кучи обычно реализуется очередь с приоритетами --- структура, позволяющая хранить объекты с приоритетами (например задания с приоритетами), извлекать самый приоритетный объект, добавлять новые объекты, быстро обновлять их приоритеты.

 

Рисунок  SEQ Рисунок \* ARABIC 1

 

1.2. Области применения

Кучи являются основной структурой данных во многих приложениях. В том числе, они применяются:

 

1.3. Свойства и операции на кучах

В общем случае куча представляет собой одно или несколько деревьев с явно выделенными корнями, элементы хранятся в вершинах. Основное свойство кучи (heap order): ключ каждой вершины не меньше, чем ключ её родителя. В дальнейшем корень дерева T будем обозначать как root(T), а значение ключа в вершине t как value(t).

Основными операциями на кучах можно считать:

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

 


1.4. Понятие фибоначчиевы кучи

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

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

К сожалению, скрытые константы в асимптотических оценках трудоемкости велики и использование фибоначчиевых куч редко оказывается целесообразным: обычные двоичные ( -ичные) кучи на практике эффективнее. С практической точки зрения желательно придумать структуру данных с теми же асимптотическими оценками, но с меньшими константами. Такие кучи будут рассмотрены в следующих разделах.

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

Строение фибоначчиевой кучи. Каждая фибоначчиева куча состоит из нескольких деревьев. В отличие от биномиальных деревьев, здесь дети любого узла могут записываться в любом порядке. Они связываются в двусторонний циклический список. Каждый узел этого списка имеет поля и , указывающие на его соседей в списке. На рис. 1.0 показано схематическое строение фибоначчиевой кучи.

Рисунок  SEQ Рисунок \* ARABIC 2

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

Помимо указанной информации, каждый узел имеет поле , где хранится его степень (число детей), а также поле . В этом поле хранится булевское значение. Смысл его таков: истинно, если узел потерял ребенка после того, как он в последний раз сделался чьим-либо потомком. Позже будет ясно, как и когда это поле используется.

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

 

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

Потенциал. При анализе учетной стоимости операций используют метод потенциала. Пусть — число деревьев в корневом списке кучи , а — количество помеченных узлов. Потенциал определяется формулой

 

В каждый момент времени в памяти может храниться несколько куч; общий потенциал по определению равен сумме потенциалов всех этих куч. В дальнейшем мы выберем единицу измерения потенциала так, чтобы единичного изменения потенциала хватало для оплаты операций (формально говоря, мы умножим потенциал на подходящую константу). В начальном состоянии нет ни одной кучи и потенциал равен . Как и положено, потенциал всегда неотрицателен.

Максимальная степень Через обозначим верхнюю границу для степеней узлов в кучах, которые могут появиться при выполнении операций. Аргументом функции является общее число всех узлов в куче, обозначаемое через .

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

Впоследствии Д.Дрисколл и Р.Тарьян  разработали структуру данных, называемую , как замену для фибоначчиевых куч. Есть две разновидности такой структуры данных. Одна из них дает те же оценки учетной стоимости, что и фибоначчиевы кучи. Другая — позволяет выполнять операцию за время в худшем случае, а операции и Delete — за время в худшем случае. Эта структура данных имеет также некоторые преимущества по сравнению с фибоначчиевыми кучами при использовании в параллельных алгоритмах.

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

  1. Существует явная ссылка на минимальный элемент.
  2. У каждой вершины есть ссылка на правый и левый элемент в двусвязном списке содержащим эту вершину.
  3. У каждой вершины есть ссылка child указывающая на одну из вершин спика ее детей.
  4. У каждой вершины есть ссылка parent указывающая на родителя.
  5. У каждой вершины есть булевское поле marked использующаяся при уменьшение ключа (см. ниже). Оно истинно если вершина потеряла ребенка после того как сделалась чьим-нибудь ребенком.
  6. Список содержащей минимальную вершину называется корневым списком и родители всех его вершин отсутствуют.

Рассмотрим теперь реализуемые алгоритмы по отдельности.


1.5. Добавление элемента

Добавим нашу вершину в корневой список. Если окажется, что значение её ключа меньше минимального, то она становиться новой минимальной вершиной.

Создание пустой кучи

Ссылка minElement зануляется.

Удаление минимального элемента

Удаление минимального элемента состоит из двух частей. Сначала мы удаляем минимальную вершину из кучи, а всех ее детей добляем в корневой список. После этого мы объединяем вершины из корневого списка в вершины большей степени. Для этого мы создаем массив ссылок на элементы нашей кучи (индекс соответствует степени вершины). Просмотрим все вершины корневого списка занося их в массив, если окажется, что тот элемент, куда мы хотим занести нашу вершину, уже занят, то мы объединим эти две вершины в одну большей степени, сделав вершину с большим ключом ребенком вершины с меньшим ключом. Получившуюся вершину попробуем опять занести в массив и т. д. После добавим все вершины из массива в корневой спиок, находя паралельно минимум.

 

Уменьшение ключа

Данный алгоритм делится на два случая:

  1. Новый ключ вершины больше ключа родителя. Тогда достаточно уменьшить ключ вершины до нового значения.
  2. Новый ключ вершины меньше ключа родителя. Тогда перенесем нашу вершину в корневой список. После этого рассмотрим цепочку предков нашей вершины (её родитель, родитель ее родителя и т. д.). Найдем в этой цепочке первую неотмеченную вершину. Все вершины до нее переместим в корневой список, а ее отметим.

Удаление вершины

Для удаление вершины сначала уменьшим ее значение до «минус бесконечности», а потом удалим минимальную вершину.

 

1.6. Время выполнения различных операций для трёх видов сливаемых куч (n – общее число элементов в кучах на момент операции).

Процедура

Двоичные кучи
(в худшем случае)

Биномиальные кучи
(в худшем случае)

Фибоначчиевы кучи
(учётная стоимость)

Создание

Q(1)

Q(1)

Q(1)

Вставка

Q(log n)

O(log n)

Q(1)

Найти мин.

Q(1)

O(log n)

Q(1)

Удалить мин.

Q(log n)

Q(log n)

O(log n)

Слить

Q(n)

O(log n)

Q(1)

Уменьшить ключ

Q(log n)

Q(log n)

Q(1)

Удалить

Q(log n)

Q(log n)

O(log n)

 


1.7. Оценки времени работы

Сводная таблица амортизированного времени работы:

 

Операция

Binary

Leftist

Top-Down Skew

Bottom-Up Skew

Pairing

Binomial

Fibonacci

2-3

Soft

MAKE

O(1)

O(1)

O(1)

O(1)

O(1)

O(1)

O(1)

O(1)

O(1)

INSERT

O(log N)

O(log N)

O(log N)

O(1)

O(log N) *

O(log N)

O(1)

O(1)

O(log 1/E)

MELD

O(N)

O(log N)

O(log N)

O(1)

O(log N) *

O(log N)

O(1)

O(log N)

O(1)

FIND-MIN

O(1)

O(1)

O(1)

O(1)

O(1)

O(log N)

O(1)

O(1)

O(1)

DELETE-MIN

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(1)

DECREASE

O(log N)

O(log N)

O(log N)

O(log N)

O(log N) *

O(log N)

O(1)

O(1)

O(1)

DELETE

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(log N)

O(1)

 

* Для Pairing куч операции добавления элемента, уменьшения ключа и слияния гипотетически выполняются за время O(1), но данная оценка еще не доказана.


Глава II.  Пример реализации алгоритма Дейкстры  в среде Delphi

2.1. Алгоритм Дейкстры

Алгори?тм Де?йкстры — алгоритм на графах , изобретенный Э. Дейкстрой . Находит кратчайшее расстояние от одной из вершин графа до всех остальных. Алгоритм работает только для графов без рёбер отрицательного веса.

Неформальное определение.

Вариант 1. Дана сеть автомобильных дорог, соединяющих города Львовской области. Найти кратчайшие расстояния от Львова до каждого города области (если двигаться можно только по дорогам).

Вариант 2. Имеется некоторое количество авиарейсов между городами мира, для каждого известна стоимость. Найти минимальную стоимость маршрута (возможно, с пересадками) от Копенгагена до Новосибирска .

Вариант 3. Есть план города с нанесёнными на него местами расположения пожарных частей. Определить ближайшую к каждому дому пожарную станцию.

Формальное определение.

Дан простой взвешенный граф G ( V , E ) без петель и дуг отрицательного веса. Найти кратчайшее расстояние от некоторой вершины a графа G до всех остальных вершин этого графа.

 Неформальное определение.

Каждой вершине из V сопоставим метку — минимальное известное расстояние от этой вершины до a . Алгоритм работает пошагово — на каждом шаге он «посещает» одну вершину и пытается уменьшать метки. Работа алгоритма завершается, когда все вершины посещены.

Инициализация . Метка самой вершины a полагается равной 0, метки остальных вершин — бесконечности. Это отражает то, что расстояния от a до других вершин пока неизвестны. Все вершины графа помечаются как непосещенные.

Шаг алгоритма . Если все вершины посещены, алгоритм завершается. В противном случае из еще не посещенных вершин выбирается вершина u , имеющая минимальную метку. Мы рассматриваем всевозможные маршруты, в которых u является предпоследним пунктом. Вершины, соединенные с вершиной u ребрами, назовем соседями этой вершины. Для каждого соседа рассмотрим новую длину пути, равную сумме текущей метки u и длины ребра, соединяющего u с этим соседом. Если полученная длина меньше метки соседа, заменим метку этой длиной. Рассмотрев всех соседей, пометим вершину u как посещенную и повторим шаг.

Описание

В простейшей реализации для хранения чисел d [ i ] можно использовать массив чисел, а для хранения принадлежности элемента множеству U — массив булевских переменных.

В начале алгоритма расстояние для начальной вершины полагается равным нулю, а все остальные расстояния заполняются большим положительным числом (большим максимального возможного пути в графе ). Массив флагов заполняется нулями. Затем запускается основной цикл.

На каждом шаге цикла мы ищем вершину с минимальным расстоянием и флагом равным нулю. Затем мы устанавливаем в ней флаг в 1 и проверяем все соседние с ней вершины. Если в ней расстояние больше, чем сумма расстояния до текущей вершины и длины ребра, то уменьшаем его. Цикл завершается когда флаги всех вершин становятся равны 1, либо когда у всех вершин c флагом 0 . Последний случай возможен, если и только если граф G несвязан.

В разработанном приложении рассчитывается расстояние от выбранной пожарной части до всех остальных города N.

Технические задачи:

  1. разработка интерфейса;
  2. реализация ввода данных пользователем;
  3. осуществление расчета расстояния;
  4. организация вывода результата пользователю.


2.2. Интерфейс

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

 

При нажатии на кнопку «задать расстояние случайно» задается расстояние при помощи random из максимально допустимой длины MAXPATH. 

При нажатии кнопки «рассчитать расстояние» программа сначала заполняет матрицу весов, т.е. перебрасывает пути из таблицы в матрицу, потом проверяет, выбрана ли начальная часть. Если начало выбрано пользователем, то вначале находится прямой путь между частями, а после не прямой. И в конце работы программы выводится результат- все допустимые пути.         

Если начальная пожарная часть не выбрана, то об этом сообщается пользователю в виде сообщения.

При нажатии «очистить» происходит очистка таблицы значений и окна вывода результатов.


2.3. Кодовая реализация

         Первая процедура TForm1.Button4Click задает пути случайным образом.

         Листинг 1:

flag: real; // существует ли путь

begin

  for i:=1 to StringGrid1.ColCount-1 do // определяется кол- во столбцов

  begin

    for j:=i+1 to StringGrid1.RowCount-1 do // определяется кол- во строк

      begin

        flag := random;

        if (flag>0.5) then

          begin

            StringGrid1.Cells[i,j] := IntToStr(random(MAX));// значения из const

            StringGrid1.Cells[j,i] := StringGrid1.Cells[i,j];// заполняет таблицу

          end;

      end;

  end;

После этого происходит заполнение матрицы весов.

         Листинг 2:

for i:=0 to CHCount-1 do // счетчик на значения

    Weights[i,i] := 0; // из части в сам себя

  for i:=0 to CHCount-1 do // счетчик  на значения

    for j:=0 to CHCount-1 do // счетчик на значения

      begin

        if (StringGrid1.Cells[i + 1, j + 1] <> '') then

          Weights[i, j] := StrToInt(StringGrid1.Cells[i + 1, j + 1]);

      end; // Если индекс ячейки не относится к шапке, то происходит заполнение

Далее при нажатии кнопки «Рассчитать» происходит вызов процедуры для расчета, которая состоит из четырех различных процедур.

Листинг 3:

GetWeightsMatrix; // перебрасываем пути в матрицу

  FirstCountStep; // инициализируем расчет

  StraightWay;    // находим прямые пути

  GoCount; // запускаем расчет

Процедура TForm1.FirstCountStep проверяет выбрана ли  начальная часть, и если нужно, то сообщает об ошибке.

Листинг 4:

first := -1;

  for i := 0 to CHCount - 1 do // счетчик для определения  начальной части

    begin

      if ListBox1.Selected[i] then // если часть выбрана

        first := i; // то присваивается значение начального пути

    end;

  if (first = -1) then // если не выбрана

    begin

      MessageDlg('Ошибка: вы не выбрали начальную часть в списке!',

      mtError, [mbOK], 0); // то выходит сообщение об ошибке

Процедура TForm1.FormCreate задает части в интетрфейсе.

Листинг 5:

StringGrid1.Cells[0, 0] := 'часть';

  for i:= 1 to CHCount do

    begin

      StringGrid1.Cells[0, i] := CH[i];

      StringGrid1.Cells[i, 0] := CH[i];

      Listbox1.Items[i-1] := CH[i];

Процедура TForm1.StraightWay находит прямой путь между частями.

Листинг 6:

for i:= 1 to CHCount do // цикл проходящий все части

  begin

    if Weights[first, i] <> 0 then

      Memo1.lines.Add(ListBox1.Items[first] + '=>' + INtToStr(i) +

      '(' + IntToStr(Weights[first, i]) + ')'); // выводится в компоненте Memo1 путь

Процедура TForm1.GoCount находит непрямой путь между частями.

Листинг 7:

n := 0; // значение пути

  str := (ListBox1.Items[first] + '=>');

  for j := 1 to CHCount do // счетчик

  begin

   for i := 0 to CHCount-1 do // счетчик

      begin

        if Weights[first, i] <> 0 then // прямой путь

          if Weights[i, j] <> 0 then // непрямой путь

            begin

              n := n + Weights[first, i] + Weights[i, j]; // просчитывается  путь прямой + непрямой

              str := str + ListBox1.items[i] + '=>';

            end;

    end;

  Memo1.Lines.Add(str + IntToStr(j) + '('+IntToStr(n)+')') // выводится результат

Процедура TForm1.Button1Click производит очистку.

Листинг 8:

for i:= 1 to CHCount do // счетчик

    for j:= 1 to CHCount do // счетчик

    begin

      StringGrid1.Cells[j, i] := ''; // очистка

    end;

    Memo1.Lines.Clear; // очистка

 

Заключение

В первой главе данной курсовой работы было рассмотрено понятие фибоначчиевы кучи, их основные свойства и операции над ними.

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

         Во второй главе был реализован алгоритм Дейкстры на примере задачи о пожарных частях.

Сложность алгоритма Дейкстры зависит от способа нахождения вершины v , а также способа хранения множества непосещенных вершин и способа обновления меток. Обозначим через n количество вершин, а через m — количество ребер в графе G .

Нетрудно показать, что скорость работы алгоритма при использовании фибоначчиевых куч является асимптотически оптимальной и улучшить её нельзя. Так, с одной стороны, задачу сортировки массива из n элементов можно свести к задаче о поиске кратчайших путей на графе из n вершин; с другой стороны, алгоритму требуется просмотреть все ребра графа, хотя бы по одному разу.

Литература

  1. Ананий В. Левитин Глава 9. Жадные методы: Алгоритм Дейкстры // Алгоритмы: введение в разработку и анализ = Introduction to The Design and Analysis of Aigorithms. — М.: «Вильямс» , 2006. — С. 189-195. — ISBN 0-201-74395-7
  2. Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — М.: МЦНМО, 2001.
  3. Статьи «Фибоначчиевы кучи» и «Алгоритм Дейкстры» сайта www.wikipedia.org.
  4. Э. Рейнгольд, Ю. Нивергельд, Н. Део. Комбинаторные алгоритмы. Теория и практика. Пер. с англ. – М., Мир, 1980.
  5. Ульман Д.Д.Алгоритм Дейкстры. – «Intertera», апр. 2007.

 


Приложение

Приложение 1. Листинг программы «Алгоритм Дейкстры».

unit Unit1;

interface

uses

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

  Dialogs, StdCtrls, Grids, jpeg, ExtCtrls;

const

  MAX = 200; // максимальная длина пути между двумя вершинами

  CHCOUNT = 6; // количество частей

type

  TForm1 = class(TForm)

    StringGrid1: TStringGrid;

    Label1: TLabel;

    Memo1: TMemo;

    Button4: TButton;

    Button6: TButton;

    ListBox1: TListBox;

    Label2: TLabel;

    Button1: TButton;

    procedure Button4Click(Sender: TObject);

    procedure Button6Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure Button1Click(Sender: TObject);

  private

    // матрица весов (расстояний между частями)

    Weights: array [0..CHCOUNT-1, 0..CHCOUNT-1] of integer;

    // индекс части- пункта отправления

    first: integer;

    procedure GetWeightsMatrix;

    procedure FirstCountStep;

    procedure GoCount;

    procedure StraightWay;

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

const CH: array [1..6] of string[3]=

                ('1-я', '2-я', '3-я',

                '4-я', '5-я', '6-я');

 

procedure TForm1.Button4Click(Sender: TObject); // задает пути между частями случайным образом

var

  i, j: integer;

  flag: real; // существует ли путь

begin

  for i:=1 to StringGrid1.ColCount-1 do

  begin

    for j:=i+1 to StringGrid1.RowCount-1 do

      begin

        flag := random;

        if (flag>0.5) then

          begin

            StringGrid1.Cells[i,j] := IntToStr(random(MAX));

            StringGrid1.Cells[j,i] := StringGrid1.Cells[i,j];// заполняет таблицу

          end;

      end;

  end;

end;

procedure TForm1.GetWeightsMatrix;  // заполняет матрицу весов Weights

var

  i, j: integer;

begin

  for i:=0 to CHCount-1 do

    Weights[i,i] := 0; // из части в саму себя

  for i:=0 to CHCount-1 do

    for j:=0 to CHCount-1 do

      begin

        if (StringGrid1.Cells[i + 1, j + 1] <> '') then

          Weights[i, j] := StrToInt(StringGrid1.Cells[i + 1, j + 1]);

      end;

end;

 

procedure TForm1.Button6Click(Sender: TObject); вызывает процедуры для расчета

begin

  Memo1.Lines.Clear;

  GetWeightsMatrix; // перебрасывает пути в матрицу

  FirstCountStep; // инициализирует расчет

  StraightWay;    // находит прямые пути

  GoCount; // запускает расчет

end;

 

procedure TForm1.FirstCountStep;   // проверяет, выбрана ли часть из списка

var

  i: integer;

begin

  first := -1;

  for i := 0 to CHCount - 1 do

    begin

      if ListBox1.Selected[i] then

        first := i;

    end;

  if (first = -1) then

    begin

      MessageDlg(‘ ошибка: вы не выбрали начальную часть в списке!',

      mtError, [mbOK], 0);

      exit;

    end;

end;

 

procedure TForm1.FormCreate(Sender: TObject);  // задает части в интерфейсе

var

  i: integer;

begin

  StringGrid1.Cells[0, 0] := 'часть';

  for i:= 1 to CHCount do

    begin

      StringGrid1.Cells[0, i] := CH[i];

      StringGrid1.Cells[i, 0] := CH[i];

      Listbox1.Items[i-1] := CH[i];

    end;

end;

 

procedure TForm1.StraightWay;    // находит прямой путь

var

  i : integer;

begin

  for i:= 1 to CHCount do

  begin

    if Weights[first, i] <> 0 then

      Memo1.lines.Add(ListBox1.Items[first] + '=>' + INtToStr(i) +

      '(' + IntToStr(Weights[first, i]) + ')');

  end;

end;

 

procedure TForm1.GoCount;     // находит непрямой путь между частями и вычисляет расстояние

var

  i, n, j : integer;

  str : string;

begin

  n := 0;

  str := (ListBox1.Items[first] + '=>');

  for j := 1 to CHCount do

  begin

   for i := 0 to CHCount-1 do

      begin

        if Weights[first, i] <> 0 then

          if Weights[i, j] <> 0 then

            begin

              n := n + Weights[first, i] + Weights[i, j];

              str := str + ListBox1.items[i] + '=>';

            end;

    end;

  Memo1.Lines.Add(str + IntToStr(j) + '('+IntToStr(n)+')')

end;

end;

 

procedure TForm1.Button1Click(Sender: TObject); // очистка

var

  i, j: integer;

begin

  for i:= 1 to CHCount do

    for j:= 1 to CHCount do

    begin

      StringGrid1.Cells[j, i] := '';

    end;

    Memo1.Lines.Clear;

  end;

end.


Приложение 2. Тестовое задание.

Рассмотрим выполнение алгоритма на примере графа, показанного на рисунке. Пусть требуется найти расстояния от 1-й вершины до всех остальных.

Кружками обозначены вершины, линиями — пути между ними (ребра графа). В кружках обозначены номера вершин, над ребрами обозначена их «цена» — длина пути. Рядом с каждой вершиной красным обозначена метка — длина кратчайшего пути в эту вершину из вершины 1.

Первый шаг . Рассмотрим шаг алгоритма Дейкстры для нашего примера. Минимальную метку имеет вершина 1. Ее соседями являются вершины 2, 3 и 6.

Первый по очереди сосед вершины 1 — вершина 2, потому что длина пути до нее минимальна. Длина пути в нее через вершину 1 равна кратчайшему расстоянию до вершины 1 + длина ребра, идущего из 1 в 2, то есть 0 + 7 = 7. Это меньше текущей метки вершины 2, поэтому новая метка 2-й вершины равна 7.

Аналогичную операцию проделываем с двумя другими соседями 1-й вершины — 3-й и 6-й.

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

Второй шаг' . Шаг алгоритма повторяется. Снова находим «ближайшую» из непосещенных вершин. Это вершина 2 с меткой 7.

Снова пытаемся уменьшить метки соседей выбранной вершины, пытаясь пройти в них через 2-ю. Соседями вершины 2 являются 1, 3, 4.

Первый (по порядку) сосед вершины 2 — вершина 1. Но она уже посещена, поэтому с 1-й вершиной ничего не делаем.

Следующий сосед вершины 2 — вершина 4. Если идти в неё через 2-ю, то длина такого пути будет = кратчайшее расстояние до 2 + расстояние между вершинами 2 и 4 = 7 + 15 = 22. Поскольку 22< , устанавливаем метку вершины 4 равной 22.

Ещё один сосед вершины 2 — вершина 3. Если идти в неё через 2, то длина такого пути будет = 7 + 10 = 17. Но текущая метка третьей вершины равна 9<17, поэтому метка не меняется.

Все соседи вершины 2 просмотрены, замораживаем расстояние до неё и помечаем ее как посещенную.

Третий шаг . Повторяем шаг алгоритма, выбрав вершину 3. После ее «обработки» получим такие результаты:

 

Дальнейшие шаги . Повторяем шаг алгоритма для оставшихся вершин (Это будут по порядку 6, 4 и 5).

Завершение выполнения алгоритма . Алгоритм заканчивает работу, когда вычеркнуты все вершины. Результат его работы виден на последнем рисунке: кратчайший путь от вершины 1 до 2-й составляет 7, до 3-й — 9, до 4-й — 20, до 5-й — 20, до 6-й — 11.

 

также в рубрике Курсовые работы:

viagra pfizer apotheke
viagra pfizer apotheke