Задачи о потоках в сетях
Это руководство было изначально предоставлено Арпитом Бхатией (Arpit Bhatia).
В теории графов сеть потоков (также известная как транспортная сеть) представляет собой ориентированный граф, в котором каждое ребро имеет пропускную способность и принимает поток. Величина потока через ребро не может превышать его пропускную способность.
Часто в исследовании операций ориентированный граф называют сетью, вершины — узлами, а ребра — дугами.
Поток должен удовлетворять ограничению, согласно которому величина потока в узел должна быть равна величине потока из него, если только он не является источником, имеющим только исходящий поток, или приемником, имеющим только входящий поток.
С помощью сети можно моделировать трафик в компьютерной сети, циркуляцию со спросом, движение жидкости в трубах, движение токов в электрической цепи или иную подобную систему, в которой что-либо перемещается по сети узлов.
Для этого руководства требуются следующие пакеты.
using JuMP
import HiGHS
Задача о кратчайшем пути
Предположим, что каждой дуге графа назначена скалярная стоимость и что стоимость прямого пути определяется как сумма стоимостей его дуг.
Для пары узлов задача о кратчайшем пути состоит в нахождении прямого пути, соединяющего эти узлы и имеющего минимальную стоимость.
где равно , если — это начальный узел, , если — это конечный узел, и в остальных случаях.
G = [
0 100 30 0 0
0 0 20 0 0
0 0 0 10 60
0 15 0 0 50
0 0 0 0 0
]
n = size(G)[1]
b = [1, -1, 0, 0, 0]
shortest_path = Model(HiGHS.Optimizer)
set_silent(shortest_path)
@variable(shortest_path, x[1:n, 1:n], Bin)
# Дуги с нулевой стоимостью не являются частью пути, так как они не существуют.
@constraint(shortest_path, [i = 1:n, j = 1:n; G[i, j] == 0], x[i, j] == 0)
# Ограничение сохранения потока
@constraint(shortest_path, [i = 1:n], sum(x[i, :]) - sum(x[:, i]) == b[i],)
@objective(shortest_path, Min, sum(G .* x))
optimize!(shortest_path)
@assert is_solved_and_feasible(shortest_path)
objective_value(shortest_path)
55.0
value.(x)
5×5 Matrix{Float64}:
0.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 1.0 0.0
0.0 1.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
Задача о присваивании
Предположим, что есть человек и предметов и их нужно сопоставить по принципу «один к одному». Для человека предмет имеет ценность , и нужно присвоить предметы людям так, чтобы общая ценность была максимальной.
Также установлено ограничение, согласно которому человеку предмет может быть присвоен только в том случае, если принадлежит заданному множеству пар .
С математической точки зрения нужно найти множество пар «человек — предмет» из такое, чтобы предметы не повторялись, а общая ценность была максимальной.
G = [
6 4 5 0
0 3 6 0
5 0 4 3
7 5 5 5
]
n = size(G)[1]
assignment = Model(HiGHS.Optimizer)
set_silent(assignment)
@variable(assignment, y[1:n, 1:n], Bin)
# Одному человеку можно присвоить только один предмет.
@constraint(assignment, [i = 1:n], sum(y[:, i]) == 1)
# Один предмет может быть присвоен только одному человеку.
@constraint(assignment, [j = 1:n], sum(y[j, :]) == 1)
@objective(assignment, Max, sum(G .* y))
optimize!(assignment)
@assert is_solved_and_feasible(assignment)
objective_value(assignment)
20.0
value.(y)
4×4 Matrix{Float64}:
-0.0 1.0 -0.0 0.0
0.0 0.0 1.0 0.0
1.0 0.0 0.0 -0.0
-0.0 0.0 0.0 1.0
Задача о максимальном потоке
В задаче о максимальном потоке имеется граф с двумя специальными узлами: , обозначаемым как , и , обозначаемым как .
Цель состоит в том, чтобы обеспечить как можно больший поток из в с соблюдением ограничений пропускной способности.
G = [
0 3 2 2 0 0 0 0
0 0 0 0 5 1 0 0
0 0 0 0 1 3 1 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 4
0 0 0 0 0 0 0 2
0 0 0 0 0 0 0 4
0 0 0 0 0 0 0 0
]
n = size(G)[1]
max_flow = Model(HiGHS.Optimizer)
@variable(max_flow, f[1:n, 1:n] >= 0)
# Ограничения пропускной способности
@constraint(max_flow, [i = 1:n, j = 1:n], f[i, j] <= G[i, j])
# Ограничения сохранения потока
@constraint(max_flow, [i = 1:n; i != 1 && i != 8], sum(f[i, :]) == sum(f[:, i]))
@objective(max_flow, Max, sum(f[1, :]))
optimize!(max_flow)
@assert is_solved_and_feasible(max_flow)
objective_value(max_flow)
6.0
value.(f)
8×8 Matrix{Float64}:
-0.0 3.0 2.0 1.0 -0.0 -0.0 -0.0 -0.0
0.0 0.0 0.0 0.0 2.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 1.0 -0.0 1.0 0.0
-0.0 -0.0 -0.0 0.0 -0.0 1.0 -0.0 -0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0