Вы находитесь на странице: 1из 15

ОДЕСЬКИЙ НАЦІОНАЛЬНИЙ ПОЛІТЕХНІЧНИЙ УНІВЕРСИТЕТ

ІНСТИТУТ КОМП'ЮТЕРНИХ СИСТЕМ


КАФЕДРА ІНФОРМАЦІЙНИХ СИСТЕМ

Розрахунково-графічна робота
З дисципліни: «Теорія алгоритмів»
     На тему: «Вирішіть задачу визначення найкоротшого шляху для пасажира
метрополітену, який би дозволяв йому переміщатися від однієї
заданої станції до іншої заданої станції, використовуючи граф
підземних комунікацій»

Виконав:
студент групи АI-193
Узунов А.Д.

Перевірила:
Арсірій О.О.

Одесса 2020
Тема РГР – Решите задачу определения кратчайшего пути для пассажира
метрополитена, который бы позволял ему перемещаться от одной заданной
станции к другой заданной станции, используя граф подземных
коммуникаций.
Цель: Разработка алгоритма для определения кратчайшего пути при
заданных входных данных.
Описание входных и выходных данных: Входные данные представлены в
виде соединяющихся между собой узлов с установленным значением весов(в
нашем случае значение весов – время пути от станции до станции).
Выходные данный представляют из себя результат выполнения операции
поиска кратчайшего пути по алгоритму Дейкстры (список узлов, длина
минимального пути).
Разработка общей схемы алгоритма: Основная цель алгоритма -
определить кратчайший путь между начальным узлом и заданым конечным.
Учитывая положительно взвешенный граф и начальный узел, алгоритм
определяет кратчайший путь и расстояние от источника(source) до конечной
точки(end) :
Будет использоваться алгоритм Дейкстры, так как он легко реализуем и
имеет относительно небольшую вычислительную сложность (О(n^2))
Чтобы отслеживать процесс, нам нужно иметь два разных набора узлов,
установленных и неустановленных.
Установленные узлы - это узлы с известным минимальным расстоянием от
источника. Набор неустановленных узлов собирает узлы, к которым мы
можем добраться из источника, но мы не знаем минимального расстояния от
начального узла.
Cписок шагов, которые необходимо выполнить для решения поставленной
задачи:
1. Установите расстояние от source до нуля.
2. Установите все другие расстояния на бесконечное значение.
3. Мы добавляем source в набор неустановленных узлов.
Пока набор неустановленных узлов не пуст, мы:
1*. Выбираем узел оценки из набора неустановленных узлов, оценочный узел
должен быть тем, у которого наименьшее расстояние от источника.
2*. Рассчитываем новые расстояния до прямых соседей, сохраняя самые
низкие расстояние при каждой оценке.
3*. Добавляем соседей, которые еще не установлены, в набор
неустановленных узлов.
Эти этапы можно объединить в два этапа: инициализация и оценка.
Инициализация:
Как часть процесса инициализации, нам нужно присвоить значение 0 узлу
source (мы знаем, что расстояние от узла source до узла source, очевидно,
равно 0)
Таким образом, каждый узел в остальной части графа будет отличаться
предшественником и расстоянием:
Чтобы завершить процесс инициализации, нам нужно добавить узел source к
неустановленным узлам, чтобы он был выбран первым на этапе оценки.
Оценка:
Теперь, когда у нас инициализирован наш граф, мы выбираем узел с
наименьшим расстоянием от неустановленного набора, а затем оцениваем
все смежные узлы, которые не находятся в установленных узлах:
Идея состоит в том, чтобы добавить вес ребра к расстоянию узла оценки, а
затем сравнить его с расстоянием назначения.
Узел source затем перемещается из установленных узлов в установленные
узлы.
Узлы смежные узлы добавляются к неустановленным узлам, потому что они
могут быть достигнуты, но их необходимо оценить.
Теперь, когда у нас есть два узла в неустановленном множестве, мы
выбираем тот, у которого наименьшее расстояние, и повторяем, пока не
достигнем конечной точки:
Реализация Java:
В этой реализации мы представим граф в виде набора узлов:
public class Graph {
private Set<Node> nodes = new HashSet<>();
public void addNode(Node nodeA) {
nodes.add(nodeA);
}
}
Узел может быть описан с помощью name , LinkedList со ссылкой на
shortestPath , distance из источника и списка смежности с именем
adjacentNodes :
public class Node {
private String name;
private List<Node> shortestPath = new LinkedList<>();
private Integer distance = Integer.MAX__VALUE;
Map<Node, Integer> adjacentNodes = new HashMap<>();
public void addDestination(Node destination, int distance) {
adjacentNodes.put(destination, distance);
}
public Node(String name) {
this.name = name;
}

}
Атрибут adjacentNodes используется для связи непосредственных соседей с
длиной ребра.
Что касается атрибута shortestPath , это список узлов, который описывает
кратчайший путь, рассчитанный из начального узла.
По умолчанию все расстояния узлов инициализируются с помощью
Integer.MAX_VALUE, чтобы имитировать бесконечное расстояние, как
описано в шаге инициализации.
Описание программной реализации алгоритма:
На вход статического метода calculateShortestPathFromSource подается
объект типа Graph, начальный узел, конечный узел
class Dijkstra {

public static Graph calculateShortestPathFromSource(Graph graph, Node


source, Node end) {
source.setDistance(0);

Set<Node> settledNodes = new HashSet<>();


Set<Node> unsettledNodes = new HashSet<>();
unsettledNodes.add(source);

while (unsettledNodes.size() != 0) {
Node currentNode = getLowestDistanceNode(unsettledNodes);
unsettledNodes.remove(currentNode);
for (Map.Entry< Node, Integer> adjacencyPair:
currentNode.getAdjacentNodes().entrySet()) {
Node adjacentNode = adjacencyPair.getKey();
Integer edgeWeight = adjacencyPair.getValue();
if (!settledNodes.contains(adjacentNode)) {
CalculateMinimumDistance(adjacentNode, edgeWeight, currentNode,
graph,end);
unsettledNodes.add(adjacentNode);

}
}
settledNodes.add(currentNode);
}
graph.setNodes(settledNodes);
return graph;
}

Метод getLowestDistanceNode () возвращает узел с наименьшим


расстоянием от заданного количества неустановленных узлов, а метод
calculateMinimumDistance () сравнивает фактическое расстояние с вновь
рассчитанным, следуя недавно исследованному пути:
private static Node getLowestDistanceNode(Set <Node> unsettledNodes) {
Node lowestDistanceNode = null;
int lowestDistance = Integer.MAX_VALUE;
for (Node node: unsettledNodes) {
int nodeDistance = node.getDistance();
if (nodeDistance < lowestDistance) {
lowestDistance = nodeDistance;
lowestDistanceNode = node;
}
}
return lowestDistanceNode;
}

private static void CalculateMinimumDistance(Node evaluationNode,


Integer edgeWeigh, Node sourceNode, Graph graph,
Node end) {

Integer sourceDistance = sourceNode.getDistance();


if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) {
evaluationNode.setDistance(sourceDistance + edgeWeigh);
LinkedList<Node> shortestPath = new
LinkedList<>(sourceNode.getShortestPath());
shortestPath.add(sourceNode);
evaluationNode.setShortestPath(shortestPath);
if (evaluationNode.equals(end))
graph.setShortestPath(shortestPath);

После расчета атрибуты shortestPath и distance устанавливаются для


заданного узла в графе, и мы можем выполнить их итерацию, чтобы
убедиться, что результаты точно соответствуют ожидаемым выходным
данным.
Визуализация пошагового выполнения задачи для подтверждения
корректности работы программы:
1. Создаем класс DataBase, который будет выполнять функции обычной
базы данных; вводим информацию об узлах, и их отношении друг с
другом.
public class DataBase {

Node nodeA = new Node("Station A");


Node nodeB = new Node("Station B");
Node nodeC = new Node("Station C");
Node nodeD = new Node("Station D");
Node nodeE = new Node("Station E");
Node nodeF = new Node("Station F");
Node nodeG = new Node("Station G");
Node nodeH = new Node("Station H");

Graph graph = new Graph();

2. Запускаем выполнение программы:


public class Main {

public static void main(String[] args) {

GraphDraw graph = new GraphDraw();


graph.setTitle("Поиск кратчайшего пути");
graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
graph.setVisible(true);

3. Инициализируемый класс GraphDraw отвечает за графическую


визуализацию и вывод результата пользователю. При нажатии на узел
графа срабатывает зарание созданный класс, имплементирующий
интерфейс ActionListner, который исходя из выбранных узлов графа
рассчитывает минимальный путь от начальной точки до конечной
public class Clicked implements ActionListener {

public void actionPerformed(ActionEvent actionEvent) {


Result.setText("Please select two nodes");
Result.setBackground(Color.pink);
CircleButton c;
CircleButton prevButton = new CircleButton();
if (clicked % 2 == 0) {
DataBase db = new DataBase();
Result.setBackground(Color.cyan);

c = (CircleButton) actionEvent.getSource();
c.prevButton = prevButton;
c.pressedCounter = clicked;
String end = c.getName();
Dijkstra.calculateShortestPathFromSource(db.getGraph(),
db.getSource(source), db.getEnd(end)).getMinPath();

if (!pathInMemory.containsKey(db.getSource(source).getName()+
db.getEnd(end).getName())) {

pathInMemory.put(db.getSource(source).getName() +
db.getEnd(end).getName(), "The shortest pass from " + source + " to " + end +
" is: "
+ db.getGraph().getMinPath() + end + " (" +
db.getGraph().getMinDistance(db.getEnd(end)) + " minutes)");
}
Result.setText(pathInMemory.get(db.getSource(source).getName()+
db.getEnd(end).getName()));

} else {
c = (CircleButton) actionEvent.getSource();
prevButton = c;
source = c.getName();
}
clicked++;
}
}

4. После того, как путь был рассчитан, он добавляется в структуру


данных, на случай если пользователь решит заново просчитать тот же
путь.
if (!pathInMemory.containsKey(db.getSource(source).getName()+
db.getEnd(end).getName())) {

pathInMemory.put(db.getSource(source).getName() +
db.getEnd(end).getName(), "The shortest pass from " + source + " to " + end + " is:
"
+ db.getGraph().getMinPath() + end + " (" +
db.getGraph().getMinDistance(db.getEnd(end)) + " minutes)");
}
Result.setText(pathInMemory.get(db.getSource(source).getName()+
db.getEnd(end).getName()));

Примеры и визуализация входных данных:


Пример
1. Входные данные расположены в классе DataBase: узлы, связи
между ними, значения весов:
nodeA.addDestination(nodeB, 20);

nodeB.addDestination(nodeE, 15);
nodeB.addDestination(nodeG, 15);
nodeB.addDestination(nodeA, 20);
nodeB.addDestination(nodeC, 35);

nodeC.addDestination(nodeB, 35);
nodeC.addDestination(nodeE, 60);
nodeC.addDestination(nodeF, 10);
nodeD.addDestination(nodeE, 30);

nodeE.addDestination(nodeD, 30);
nodeE.addDestination(nodeB, 15);
nodeE.addDestination(nodeC, 60);

nodeF.addDestination(nodeC, 10);
nodeF.addDestination(nodeG, 35);

nodeG.addDestination(nodeH, 40);
nodeG.addDestination(nodeB, 15);
nodeG.addDestination(nodeF, 35);

nodeH.addDestination(nodeG, 40);

graph.addNode(nodeA);
graph.addNode(nodeB);
graph.addNode(nodeC);
graph.addNode(nodeD);
graph.addNode(nodeE);
graph.addNode(nodeF);
graph.addNode(nodeG);
graph.addNode(nodeH);

nodes.add(nodeA);
nodes.add(nodeB);
nodes.add(nodeC);
nodes.add(nodeD);
nodes.add(nodeE);
nodes.add(nodeF);
nodes.add(nodeG);
nodes.add(nodeH);
2. Граф моделируется вручную.
3. Выбираем первый узел

4. Выбираем второй узел


Примеры и визуализация выходных данных:
После выбора пары узлов получаем результат:

При повторном выборе того же пути выводятся сохраненные


данные:
Примеры:
1.
2.

3.

4.

Анализ полученных результатов и выводы по достижению цели РГР.


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

Вам также может понравиться