Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
всё для проги / Программирование на ЯВУ-Снижко / Динамические структуры данных.doc
Скачиваний:
107
Добавлен:
26.03.2015
Размер:
397.31 Кб
Скачать

Нахождение кратчайших путей между парами вершин

Общая задача нахождения кратчайших путей – задача нахождения кратчайших путей между всеми парами вершин орграфа. Формулировка задачи: Есть орграф G, каждой дугеvwэтого орграфа сопоставлена неотрицательная стоимостьC[v,w]. Задача заключается в нахождении для каждой упорядоченной пары вершин (v,w) любого пути от вершиныvв вершинуw, длина которого минимальна среди всех возможных путей отvкw.

Можно решить эту задачу, последовательно применяя алгоритм Дейкстры для каждой вершины, объявляемой в качестве источника. Но существует прямой способ решения данной задачи, использующий алгоритм Флойда (R.W.Floyd). Для определенности положим, что вершины графа последовательно пронумерованы от 1 доn. Алгоритм Флойда использует матрицу А размераnxn, в которой вычисляются длины кратчайших путей. ВначалеA[i,j]=C[i,j] для всехij. Если дугаijотсутствует, тоC[i,j]=. Каждый диагональный элемент матрицы А равен 0.

Над матрицей А выполняется nитераций. Послеk-й итерацииA[i,j] содержит значение наименьшей длины путей из вершиныiв вершинуj, которые не проходят через вершины с номером, большимk. Другими словами, между концевыми вершинами путиiиjмогут находиться только вершины, номера которых меньше или равныk.

На k-й итерации для вычисления матрицы А применяется следующая формула:

Ak[i, j] = min (Ak-1[i, j], Ak-1[i, k] + Ak-1[k, j])

Нижний индекс kобозначает значение матрицы А послеk-й итерации, но это не означает, что существуетnразличных матриц, этот индекс используется для сокращения записи.

Для вычисления Ak[i,j] проводится сравнение стоимости пути от вершиныiк вершинеjбез участия вершиныkили другой вершины с более высоким номером со стоимостью пути от вершиныiдо вершиныkплюс стоимость пути от вершиныkдо вершиныj. Если путь через вершинуkдешевле, то величина Ak[i, j] изменяется.

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

Рис. 7. Помеченный орграф

1

2

3

1

2

3

1

0

8

5

1

0

8

5

2

3

0

2

3

0

8

3

2

0

3

2

0

A0[i, j]

A1[i, j]

1

2

3

1

2

3

1

0

8

5

1

0

7

5

2

3

0

8

2

3

0

8

3

5

2

0

3

5

2

0

A2[i, j]

A3[i, j]

Равенства Ak[i,k]=Ak-1[i,k] иAk[k,j]=Ak-1[k,j] означают, что на -й итерации элементы матрицы А, стоящие вk-й строке иk-м столбце, не изменяются. Более того, все вычисления можно выполнить с применением только одной копии матрицы А.

Пример. Функция, реализующая алгоритм Флойда.

void Floyd (float A[n][n], float C[n][n])

{

int i, j, k;

for (i=0; i<n; i++)

for (j=0; j<n; j++)

A[i][j] = C[i][j];

for (i=0; i<n; i++)

A[i][i] = 0;

for (k=0; k<n; k++)

for (i=0; i<n; i++)

for (j=0; j<n; j++)

if (A[i][k] + A[k][j] < A[i][j])

A[i][j] = A[i][k] + A[k][j];

}

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

Во многих ситуациях требуется распечатать самый дешевый путь от одной вершины к другой. Чтобы восстановить при необходимости кратчайшие пути, можно в алгоритме Флойда ввести еще одну матрицу Р, в которой элемент P[i.j]содержит вершинуk, полученную при нахождении наименьшего значенияA[i,j]. ЕслиP[i.j]=0, то кратчайший путь из вершиныiв вершинуjсостоит из одной дугиij.

Пример. Функция нахождения кратчайших путей.

void Floyd (float A[n][n],

float C[n][n], int P[n][n])

{

int i, j, k;

for (i=0; i<n; i++)

for (j=0; j<n; j++)

{

A[i][j] = C[i][j];

P[i][j] = -1;

}

for (i=0; i<n; i++)

A[i][i] = 0;

for (k=0; k<n; k++)

for (i=0; i<n; i++)

for (j=0; j<n; j++)

if (A[i][k] + A[k][j] < A[i][j])

{

A[i][j] = A[i][k] + A[k][j];

P[i][j] = k;

}

}

Для вывода на печать последовательности вершин, составляющих кратчайший путь от вершины iдо вершиныj, вызывается функцияpath(i,j), код которой приведен ниже

void path (int i, int j)

{

int k = P[i][j];

if (k==-1) return;

path (i, k);

cout<<k<<' ';

path (k, j);

}

1

2

3

1

0

3

0

2

0

0

1

3

2

0

0

Р

Рис. 8. Матрица Р для орграфа из рис. 14

Соседние файлы в папке Программирование на ЯВУ-Снижко