图论基础:最小路径问题
图论基础:最小路径问题
概念
图是一种抽象出的数学概念。图论是欧拉在研究柯尼斯堡七桥问题开创的数学分支。
一个图通常用一个二元组表示, G=(V(G),E(G)),其中V是非空集,称为点集 (vertex set),对于 V(G)中的每个元素,我们称其为顶点 (vertex)或节点 (node),简称点;E(G) 为 V(G) 各结点之间边的集合,称为边集 (edge set)。
当边有向时,称为有向图;当边无向时,称为无向图。
表示方法
一般我们用一个邻接矩阵来表示一张图。
添加图片注释,不超过 140 字(可选)
比如这张图,就可以表示为
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
A | 0 | 2 | 4 | Inf | Inf | Inf |
B | 2 | 0 | 5 | Inf | Inf | 4 |
C | 4 | 5 | 0 | 1 | 3 | Inf |
D | Inf | Inf | 1 | 0 | 3 | Inf |
E | Inf | Inf | 3 | 3 | 0 | 1 |
F | Inf | 4 | Inf | Inf | 1 | 0 |
邻接矩阵是对称的,对于没有直接相连的两个点,用Inf表示。
按照邻接矩阵的性质,它一定是对称的。
最短路问题
现有一个图的邻接矩阵,求从A到其他各点的最短距离。
最短路径问题有很多解法,可以用整数规划,蒙特卡洛等,但最好的算法是迪杰斯特拉算法(Dijkstra),
其基本思想是按距 (起点)从近到远为顺序,依次求得 到G各顶点最短的路径和距离,直到 (终点)。以下是算法步骤
- For every
- If
代码实现:
function [mydistance, mypath] = dijkstra(a,sb,db) %a为邻接矩阵,sb起点,db终点
n=size(a,1);% n个结点
visited(1:n) = 0;% 都没有访问过
distance(1:n) = inf;
distance(sb) = 0;%自己到自己的距离为0
visited(sb) = 1;u=sb;%更新一次,已经访问过自己。
parent(1:n) = 0;%前驱节点初始化
for i=1 : n-1
id = find(visited == 0);%查找未曾访问过的点
for v = id
if a(u,v) + distance(u) < distance(v) %起点到u的距离加(u,v)的距离小于起点到v的距离的话
distance(v) = a(u,v) + distance(u);
parent(v) = u;
end
end
temp = distance;
temp(visited == 1) = inf; %已经标号的点的距离换为无穷,防止之前的点加入筛选。
[t,u] = min(temp); %找到这一轮选取的点中距离最小的点, 顺便更新u
visited(u)=1;
end
mypath = [];
if parent(db) ~= 0 %如果有路
t=db;
mypath = db;
while t ~= sb
p=parent(t);
mypaht = [p mypath];
t = p;
end
end
mydiatance = diatance(db);
迪杰斯特拉算法有一个小问题, 就是不能计算权重有负值的点。
SPFA(贝尔曼-福特算法)和弗洛伊德等算法可以解决这个问题,见最短路 - OI Wiki (oi-wiki.org)。
MATLAB自带函数
这里讲一下matlab自带的计算最小路径的函数,它也可以计算有负边权的问题。
[P,d] = shortestpath (G, start, end, ['method', algorithm])
%method 为求解的算法,具体如下
%auto为默认算法,其中unweighted用于无权图, positive用于边权非负图
%unweighted BFS广搜求解(仅用于无权图)
%positive dijkstra算法,用于非负边权图
%mixed算法 用贝尔曼-福特算法求解(能算负边权)
用matlab画图可用graph函数绘制边权图(在2021以上matlab版本中,graph也可以绘制邻接矩阵图了)
G = graph(s, t, w);%s为起点,t为终点,w为权重
plot(G,'linewidth',2);
set(gca, 'XTick', [], 'YTick', []);%去掉数轴
%%绘制字符数串图
s={'北京','上海','南京'};
t={'上海','南京','北京'};
w=[10,20,30];
G = graph(s, t, w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2);
set(gca, 'XTick', [], 'YTick', []);%去掉数轴
%% 用邻接矩阵绘图(biograph在2021版本后已经被ban掉了)
cmat = [0 1 0 0;
1 0 1 1;
0 1 0 0;
0 1 0 0];
name = {'Node1', 'Node2', 'Node3', 'Node4'};
% 用digraph创建有向图
G = digraph(cmat, name);
% 用plot函数绘制图形
figure;
p = plot(G, 'Layout', 'circle'); % 用'circle'布局来尝试模拟'radial'效果。
% 进一步定制图形,例如设置节点颜色、大小等(可选)
p.NodeColor = 'r';
p.MarkerSize = 10;
分享一个CS的网站,可以帮助画图:Graph Editor (csacademy.com)
本文作者:West11
本文链接:https://www.cnblogs.com/cxy1114blog/p/18288098
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步