目录
零.基础知识
%warning()警告函数
%disp()打印函数
%num2str()数字转字符
%zeros(n)初始化n*n的零矩阵
%:代表矩阵的所有行或者列,两侧放置数字则代表从a到b的所有行或列
一.作图
(1)网站作图(强烈推荐)
https://csacademy.com/app/graph_editor/
需要科学上网
基本语法
[起点] [终点] [权值]
(2)matlab作图
1.无权图
G = graph(起点向量,终点向量)
plot(graph,"linewidth",a)
set(gca,'XTick',[],'YTick',[]);% 不在图中显示横纵坐标
%a设置线的宽度
% 编号必须从1开始编号,默认编号连续
% 起点向量s=[]
如果点是字符串,用元胞数组
% 起点向量s={" "}
2.有权图
多出一个w权值数组
G=graph(s,t,w)
plot(G,'EdgeLabel',G.Edges.Weight,'linewidth',2)
3.有向图
G=digraph(s,t)
二.最短路径问题
- 权重邻接矩阵
规定对角线上元素均为0,不存在的权重均为Inf正无穷
- 最短路径
最短路径上的所有子路径都是起点到该点的最短路径
(1)Dijkstra算法
分为已选顶点集合,未选顶点集合
缺点
可以用于有向图,但不能处理负权重
(2)Bellman-Ford算法
不再将结点区分为是否已访问的状态,因为该模型是利用循环来进行更新权重的,且每循环一次,算法都会更新所有的结点的信息。
缺点
Bellman-Ford算法不支持含有负权回路的图
https://blog.csdn.net/a8082649/article/details/81812000
https://www.bilibili.com/video/av43217121
- 负权回路
存在一个圈,这个圈上所有的权值之和是负数,那这就是一个负权环,也叫作负权回路。
存在福泉回路的图是不能求两点间最短路的,因为只要在负权回路上兜圈子,那所得的最短路长度可以任意小。
(3)Floyd算法
https://www.bilibili.com/video/av54668527
可以得到任意两点之间的最短路径,而上述两种算法需要指定起点和终点
算法核心:三层循环,动态规划
for k in range(self.V):
for i in range(self.V):
for j in range(self.V):
if self.D[i][k]+self.D[k][j]<self.D[i][j]:
self.D[i][j]=self.D[i][k]+self.D[k][j]
self.S[i][j]=self.S[i][k]
Floyd算法最后得到两个矩阵,一个是Distance Table距离矩阵,一个是Sequence Table次序矩阵(行坐标->列坐标需要先走到的节点).
matlab代码:可以计算出所有节点与节点的最短路径
Floyd_algorithm核心算法
% D是邻接权重矩阵
func [dist,path]=Floyd_algorithm(D)
n=size(D,1)
% 初始化dist 矩阵和path 矩阵
dist=D;
path=zeros(n);
for j=1:n
path(:,j)=j;
end
for i=1:n
path(i,i)=-1;
end
%算法部分
for k=1:n
for i=1:n
for j=1:n
if dist(i,k)+dist(k,j)<dist(i,j)
dist(i,j)=dist(i,k)+dist(k,j);
path(i,j)=path(i,k);
end
end
end
end
end
print_path函数
function []=print_path(path,dist,i,j)
if i==j
warning('起点和终点相同,请检查后重新输入')
return;
end
if path(i,j)==j
if dist(i,j)==Inf
disp(['从',num2str(i),'到',num2str(j),'没有路径可以到达'])
else
disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
disp([num2str(i),'--->',num2str(j)])
disp(['最短距离为',num2str(dist(i,j))])
end
else
k=path(i,j)
result=[num2str(i),'--->'];
while k ~=j
result=[result,num2str(k),'--->];
k=path(k,j);
end
result=[result,num2str(k)];
disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
disp(result)
disp(['最短距离为',num2str(dist(i,j))])
end
end
应用Floyd_algorithm
n = 9; %一共九个节点
D = zeros(n);
% 因为是无向图,所以权重邻接矩阵是一个对称矩阵
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)
print_path(path,dist,1,5)
缺点:
所以限于计算机的算力,在点数比较少时采用Floyd算法
三.matlab实现
(1)求最短路径
[P,d]=shortestpath(G,start,end,'Method',algorithm]
% G:输入图对象
% start:起始点
% end:目标点
% algorithm:默认为auto,auto是matlab选择的最适合该图的算法
% P:最短路径经过的结点
% d:最短距离
(2)在图中高亮出最短路径
myplot=plot(G,'EdgeLabel',G.Edges.Weight,'linewidth',2)
highlight(myplot,P,'EdgeColor','r')
(3)返回任意两点之间的最短距离
D=distances(G)
(4)找给定范围内的所有的点
[nodeIDs,dist]=nearest(G,s,d)
% 返回图形G中与节点s的距离在d之内的所有结点
% nodeIDs是符合条件的结点
% Dist是这些节点与s的距离