
- •Математический факультет
- •Введение
- •1.2. Понятие графов и их виды
- •1.3. Способы описания графов
- •1.3.1. Матричное представление графов
- •1.3.2. Теоретико-множественное представление графов
- •1.3.3. Задание графов соответствием
- •Алгоритмы на графах
- •2.1. Алгоритм Беллмана-Форда
- •2.2 Алгоритм Флойда-Уоршелла
- •Заключение
- •Список использованной литературы
2.2 Алгоритм Флойда-Уоршелла
Задан ориентированный взвешенный граф. Требуется построить для этого графа матрицу кратчайших путей между всеми парами вершин.
Алгоритм решения.
Пусть
веса дуг заданы в виде матрицы D.
Будем решать задачу методом динамического
программирования. Обозначим за
длину
кратчайшего пути между вершинами i и j,
который в качестве промежуточных
содержит только вершины с номерами, не
превосходящими k.
Рассмотрим случай, когда k=0.
Это означает, что промежуточных вершин
в путях быть не может. Значит, путь будет
существовать между теми вершинами,
между которыми по условию есть дуга.
Тогда матрицу
построим
на основе матрицы D следующим
образом. Во-первых, расстояние между
вершинами, между которыми нет дуги,
положим равным бесконечности. Во-вторых,
из вершины в неё саму всегда можно
добраться за нулевое число шагов, поэтому
если вес дуги (i,j)
положителен, то заменим его нулём. Пусть
теперь k>0.
Понятно, что искомый кратчайший путь
может либо проходить через вершину с
номером k,
либо нет. Если он проходит через эту
вершину, то его можно разбить на две
части: путь от i до k и
путь от k до j.
Поскольку оба этих пути должны являться
кратчайшими, имеем следующее рекуррентное
соотношение:
Асимптотическая
сложность алгоритма – O(),
где N –
число вершин графа.
Так же, как и в алгоритме Форда-Беллмана, объём используемой памяти можно сократить. Нам достаточно одной матрицы размерности N. Все обновления расстояний мы будем осуществлять именно в ней.
Отметим,
что при наличии в графе циклов
отрицательного веса существуют кратчайшие
пути сколь угодно малого веса. Имеет
место следующий критерий: в графе есть
циклы отрицательного веса тогда и только
тогда, когда для некоторого
i .
Задача 2
Дан взвешенный ориентированный граф из N вершин. Требуется найти в нем величину кратчайшего пути между каждой парой вершин.
Входные данные:
В
первой строке записано натуральное
число .
В каждой из следующих N
строк записано по N
чисел
— матрица весов дуг графа. Все веса
представляют собой целые неотрицательные
числа, не превосходящие 1000. Если в матрице
в i-й
строке j-м
столбце стоит 0, то это означает, что
дуги из вершины i в
вершину j
нет.
Выходные данные:
В выходной файл надо вывести матрицу кратчайших путей между каждой парой вершин графа (т.е. матрицу у которой в i-й строке j-м столбце стоит длина кратчайшего пути из вершины i в вершину j или 0 — если пути из i в j не существует).
import java.io.PrintWriter;
import java.util.Scanner;
public class Solution {
private static final int INF = 1000 * 1000 * 1000; //в качестве условной бесконечности выберем достаточно большое число 10^9
public static void main(String[] args) {
Solution solution = new Solution();
solution.solve(); //вызываем процедуру решения задачи
}
private void solve() {
Scanner scanner = new Scanner(System.in);//для считывания воспользуемся классом Scanner
PrintWriter printWriter = new PrintWriter(System.out); //для считывания воспользуемся классом PrintWriter
int vertexCount = scanner.nextInt(); //cчитываем число вершин графа
int[][] g = new int[vertexCount][vertexCount]; //граф будем хранить в матрице смежности
for (int i = 0; i < vertexCount; i++) {
for (int j = 0; j < vertexCount; j++) {
g[i][j] = scanner.nextInt(); //считываем вес ребра между вершинами i и j соответственно
if (g[i][j] == 0) {
g[i][j] = INF; //по условию если g[i][j] = 0, то это означает, что дуги из i в j нет; в этом случае расстояние между этими вершинами бесконечно велико
}
}
}
for (int k = 0; k < vertexCount; k++) {
for (int i = 0; i < vertexCount; i++) {
for (int j = 0; j < vertexCount; j++) { // Согласно алгоритму будем обновлять ответ для каждой пары вершин i и j, перебирая промежуточную вершину k
g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
}
}
}
for (int i = 0; i < vertexCount; i++) {
for (int j = 0; j < vertexCount; j++) {
if (g[i][j] == INF) {
printWriter.print(0 + " ");
}
else {
printWriter.print(g[i][j] + " "); //для каждой пары вершин выведем величину кратчайшего пути от i до j, или 0, если j не достижима из i
}
}
printWriter.println();
}
scanner.close(); //закрытие потока ввода
printWriter.close(); //закрытие потока вывода
}
}