Table of contents
1 Basic concepts of graphs
A graph in graph theory is a graph composed of a number of given points and a line connecting the two points. This graph is usually used to describe a specific relationship between certain things. Points are used to represent things, and A line connecting two points indicates that there is a relationship between the corresponding two things.
A graph can be described in mathematical language as: G(V(G),E(G))
. V(vertex)
Refers to the vertex set of the graph, E(edge)
and refers to the edge set of the graph.
Depending on whether the edges have direction, graphs can be divided into undirected graphs and directed graphs . In addition, some graphs may have weights on their edges, and such graphs are called weighted graphs .
2 How to make pictures
2.1 Draw directly
2.2 Programming and drawing
Undirected graph
graph(s,t)
: can create edges between corresponding nodes ins
and and generate a grapht
graph(s,t,w)
: An edge can be created between corresponding nodes ins
and with a weight and generate a grapht
w
To make a directed graph, just graph
change digraph
to .
1️⃣ Undirected graph
% 无权重,也可以说每条边的权重默认为1
s1 = [1,2,3,4];
t1 = [2,3,1,1];
% 函数graph(s,t):可在 s 和 t 中的对应节点之间创建边,并生成一个图
% s 和 t 都必须具有相同的元素数;这些节点必须都是从1开始的正整数,或都是字符串元胞数组。
G1 = graph(s1, t1);
plot(G1)
% 注意字符串元胞数组是用大括号包起来的哦
s2 = {
'学校','电影院','网吧','酒店'};
t2 = {
'电影院','酒店','酒店','KTV'};
G2 = graph(s2, t2);
plot(G2, 'linewidth', 2) % 设置线的宽度
% 下面的命令是在画图后不显示坐标
set( gca, 'XTick', [], 'YTick', [] );
% 有权重
s = [1,2,3,4];
t = [2,3,1,1];
w = [3,8,9,2];
% 函数graph(s,t,w):可在 s 和 t 中的对应节点之间以w的权重创建边,并生成一个图
G = graph(s, t, w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2)
set( gca, 'XTick', [], 'YTick', [] );
❗️Note:
- Note, the numbers can only be numbered consecutively starting from 1 (otherwise an error will be reported). Do not define the numbers casually by yourself, because the default numbering is consecutive, and it is possible not to write it.
s = [1,2,3,50];
t = [2,3,1,1];
G = graph(s, t);
plot(G)
2️⃣ Directed graph
% 无权图 digraph(s,t)
s = [1,2,3,4,1];
t = [2,3,1,1,4];
G1 = digraph(s, t);
plot(G1)
set( gca, 'XTick', [], 'YTick', [] );
% 有权图 digraph(s,t,w)
s = [1,2,3,4];
t = [2,3,1,1];
w = [3,8,9,2];
G2 = digraph(s, t, w);
plot(G2, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2)
set( gca, 'XTick', [], 'YTick', [] );
☀️ Summary:
- The graphs produced by Matlab are not very beautiful. If there are relatively few nodes, it is recommended to use online
3 Weighted adjacency matrix
3.1 Undirected graph
3.2 Directed graph
4 Dijkstra’s algorithm
4.1 Algorithm Overview
There are a total of nine locations from 0 to 8 in the picture. If the locations are connected by a straight line, it means that the two places can be reached directly. The value next to the straight line indicates the distance between the two places.
The starting point is 0 and the end point is 4. How to take the shortest distance?
Use Dijkstra
algorithms to solve the above problems
1️⃣ Initialization
Visited
: All nodes are unvisited;
Distance
: The distance between all nodes is Inf
;
Parent
: The parent node (previous node) of all nodes is -1, indicating that it does not exist
1️⃣ The starting point is 0, update the table:
- The access status of node 0 changes to 1
- The distance corresponding to node 0 becomes 0
- The parent node of node 0 is represented by 0. Of course, it can be represented by other symbols.
2️⃣ Update the information of the node (B) adjacent to node 0 (A). Note that the B node here is not visited.
- If the distance between A and B + the distance between A is less than the distance between B, then we update the distance between B to a smaller distance, update the parent node of B to A, and include the nodes with a smaller distance into the visited in node
3️⃣ Update the information of the node (B) adjacent to node 1 (A). Note that the B node here is not visited.
- If the distance between A and B + the distance between A is less than the distance between B, then we update the distance between B to a smaller distance, update the parent node of B to A, and include the nodes with a smaller distance into the visited in node
4️⃣ Repeat the above steps and finally get:
Based on the above results, we can get the shortest path from node 0 to node 4:
Dijkstra
The algorithm is generally used to find the shortest path in undirected graphs, and can also be used in directed graphs. However,Dijkstra
a shortcoming of the algorithm is that it cannot be used to process graphs with negative weights.
Bellman‐Ford
algorithm
In order to solve Dijkstra
the shortcoming that the algorithm cannot be used to deal with graphs with negative weights, Bellman‐Ford
an algorithm is proposed
In fact, Bellman‐Ford
the algorithm no longer distinguishes nodes into visited or not , because Bellman‐Ford
the algorithm uses loops to update weights, and every loop, Bellman‐Ford
the algorithm updates the information of all nodes.
Bellman‐Ford
The algorithm does not support graphs containing negative weight cycles (nor does Floyd's algorithm)
4.2 Code implementation
[P,d] = shortestpath(G,start,end [,'Method',algorithm])
-
Function: Return the shortest path from node to node
G
in the graphstart
end
-
Input parameters:
G
: Input graph (graph
object ordigraph
object)start
: starting nodeend
: target node[,‘Method’,algorithm]
: is an optional parameter, indicating the algorithm for calculating the shortest path. Generally we do not need to set it manually, the default isauto
-
Output parameters:
P
nodes passed by the shortest pathd
shortest distance
Sample code:
%% 注意:以下代码需要较新版本的matlab才能运行(最好是2016版本及以上)
% 如果运行出错请下载新版的matlab代码再运行
% 注意哦,Matlab中的图节点要从1开始编号,所以这里把0全部改为了9
% 编号最好是从1开始连续编号,不要自己随便定义编号
s = [9 9 1 1 2 2 2 7 7 6 6 5 5 4];
t = [1 7 7 2 8 3 5 8 6 8 5 3 4 3];
w = [4 8 3 8 2 7 4 1 6 6 2 14 10 9];
G = graph(s,t,w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2)
set( gca, 'XTick', [], 'YTick', [] );
[P,d] = shortestpath(G, 9, 4) %注意:该函数matlab2015b之后才有哦
% 在图中高亮我们的最短路径
myplot = plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2); %首先将图赋给一个变量
highlight(myplot, P, 'EdgeColor', 'r') %对这个变量即我们刚刚绘制的图形进行高亮处理(给边加上r红色)
% 求出任意两点的最短路径矩阵
D = distances(G) %注意:该函数matlab2015b之后才有
D(1,2) % 1 -> 2的最短路径
D(9,4) % 9 -> 4的最短路径
% 找出给定范围内的所有点 nearest(G,s,d)
% 返回图形 G 中与节点 s 的距离在 d 之内的所有节点
[nodeIDs,dist] = nearest(G, 2, 10) %注意:该函数matlab2016a之后才有
Output graphics:
5 Floyd's algorithm
5.1 Algorithm Overview
Floyd
The algorithm is an algorithm for solving the shortest path between any two points. It can correctly handle the shortest path problem of undirected graphs or directed graphs (negative weights are allowed, but negative weight loops cannot exist).
Floyd
Compared with the algorithm Dijkstra
or Bellman‐Ford
the algorithm, the algorithm can find the shortest path between any two points at once . The latter two algorithms can only calculate the shortest path between the given starting point and the end point after one run. Of course, Floyd
the calculation time of the algorithm is also higher than that of the latter two algorithms. The core steps of the algorithm consist of three layers of loops.
From the two conclusions observed above, it is not difficult for us to extract the following idea:
- Suppose there is a starting point A and an end point B, then for any other intermediate point M: ,
D(A,B) ≤ D(A,M) + D(M,B)
here, D(X,Y) represents the shortest distance between the two points X and Y.
Therefore, the core of Floyd's algorithm actually lies in a three-layer loop
5.2 Code implementation
☀️Realize the distance of the shortest path between any two points
☀️Find the shortest path (record the points passed by the shortest path)
Convert pseudocode to Matlab code :
1️⃣ Define Floyd
algorithm functionsFloyd_algorithm.m
function [dist,path] = Floyd_algorithm(D)
%% 该函数用于求解一个权重邻接矩阵任意两个节点之间的最短路径
% 输入:
% D是权重邻接矩阵
% 输出:
% dist是最短距离矩阵,其元素dist_ij表示表示i,j两个节点的最短距离
% path是路径矩阵,其元素path_ij表示起点为i,终点为j的两个节点之间的最短路径要经过的节点
n = size(D,1); % 计算节点的个数
% 初始化dist矩阵
dist = D;
% 下面我们来初始化path矩阵
path = zeros(n);
for j = 1:n
path(:,j) = j; % 将第j列的元素变为j
end
for i = 1:n
path(i,i) = -1; % 将主对角线元素变为-1
end
% 下面开始三个循环
for k=1:n % 中间节点k从1- n 循环
for i=1:n % 起始节点i从1- n 循环
for j=1:n % 终点节点j从1-n 循环
if dist(i,j)>dist(i,k)+dist(k,j) % 如果i,j两个节点间的最短距离大于i和k的最短距离+k和j的最短距离
dist(i,j)=dist(i,k)+dist(k,j); % 那么我们就令这两个较短的距离之和取代i,j两点之间的最短距离
path(i,j)=path(i,k); % 起点为i,终点为j的两个节点之间的最短路径要经过的节点更新为path(i,k)
% 注意,上面一行语句不能写成path(i,j) = k
end
end
end
end
end
2️⃣ Define a function that prints the shortest path between any two nodesprint_path.m
function [] = print_path(path,dist,i,j)
%% 该函数的作用是打印从i到j经过的最短路径
% 输入:
% path是使用floyd算法求出来的路径矩阵
% dist是使用floyd算法求出来的最短距离矩阵
% i是起始节点的编号
% j是终点节点的编号
% 输出:无
if i == j
warning('起点和终点相同,请检查后重新输入') % 在屏幕中提示警告信息
return; % 不运行下面的语句,直接退出函数
end
if path(i,j) == j % 如果path(i,j) = j,则有两种可能:
% (1)如果dist(i,j) 为 Inf , 则说明从i到j没有路径可以到达
if dist(i,j) == Inf
disp(['从',num2str(i),'到',num2str(j),'没有路径可以到达'])
% (2)如果dist(i,j) 不为 Inf , 则说明从i到j可直接到达,且为最短路径
else
disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
disp([num2str(i),' ---> ',num2str(j)])
disp(['最短距离为',num2str(dist(i,j))])
end
else % 如果path(i,j) ~= j,则说明中间经过了其他节点:
k = path(i,j);
result = [num2str(i),' ---> ']; % 初始化要打印的这个字符串
while k ~= j % 只要k不等于j, 就一直循环下去
result = [result , num2str(k) , ' ---> ' ]; % i先走到k这个节点处
k = path(k,j);
end
result = [result , num2str(k)];
disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
disp(result)
disp(['最短距离为',num2str(dist(i,j))])
end
end
3️⃣ Define a function that prints all the shortest paths between any two nodesprint_all_path.m
function [] = print_all_path(D)
%% 该函数的作用是求解一个权重邻接矩阵任意两个节点之间的最短路径,并打印所有的结果出来
% 输入:
% D是权重邻接矩阵
% 输出:无
[dist,path] = Floyd_algorithm(D); % 调用之前的Floyd_algorithm函数
n = size(D,1);
if n == 1
warning('请输入至少两阶以上的权重邻接矩阵') % 在屏幕中提示警告信息
return; % 不运行下面的语句,直接退出函数
end
for i = 1:n
for j = 1:n
if i ~= j % 不等号用~=表示
print_path(path,dist,i,j); % 调用之前的print_path函数
disp('-------------------------------------------')
disp(' ')
end
end
end
end
4️⃣ Convert the graph into a weighted adjacency matrix D and call Floyd
the function of the algorithm
%% 首先将图转换为权重邻接矩阵D
n = 5; %一共五个节点
D = ones(n) ./ zeros(n); % 全部元素初始化为Inf【有向图】
for i = 1:n
D(i,i) = 0; % 主对角线元素为0
end
D(1,2) = 3;
D(1,3) = 8;
D(1,5) = -4;
D(2,5) = 7;
D(2,4) = 1;
D(3,2) = 4;
D(4,3) = -5;
D(5,4) = 6;
D(4,1) = 2;
%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)
print_path(path,dist,1,5)
print_path(path,dist,1,4)
print_path(path,dist,3,1)
clc
disp('下面我们打印任意两点之间的最短距离:')
print_all_path(D)
6 Questions to Think About
Find the shortest path between any two points
Reference answer:
%% 首先将图转换为权重邻接矩阵D
n = 9; %一共9个节点
D = zeros(n); % 全部元素初始化为0 【无向图】
% 因为是无向图,所以权重邻接矩阵是一个对称矩阵
D(1,2) = 4; D(1,8) = 8;
D(2,8) = 3; D(2,3) = 8;
D(8,9) = 1; D(8,7) = 6;
D(9,7) = 6; D(9,3) = 2;
D(7,6) = 2; D(3,4) = 7;
D(3,6) = 4; D(6,4) = 14;
D(4,5) = 9; D(6,5) = 10;
D = D+D'; % 这个操作可以得到对称矩阵的另一半
for i = 1:n
for j = 1:n
if (i ~= j) && (D(i,j) == 0)
D(i,j) = Inf; % 将非主对角线上的0元素全部变为Inf
end
end
end
%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)