【Matlab】根据图生成带权邻接矩阵,并求出最短路径

图的简介

图是拓扑学中的一个重要概念,分为无向图和有向图两种。图有两个重要属性,即点(Node)和边(Edge)。在图的概念中,我们只关心点和边的连接关系而并不关系他们在图中的相对位置。
由点和边连接的图中,将边赋予一定的权重,就可以将图转换为各种问题,例如TSP(旅行商)问题、(Shortest Path)最短路径问题。本文先介绍如何借助图以及赋予的边的权值生成带权邻接矩阵,再介绍利用图求两点之间最短路径的求法。

无向图(Graph)

生成带权邻接矩阵

先介绍根据以下无向图生成带权邻接矩阵的方法:
带权邻接矩阵
假设我们已经知道了每条边的权重(红色标定),该图中有11个点,如果挨个写出需要121个元素,对于此图已经非常繁琐。因此我给大家提供一种简单的方法,只需要写出图中标定权值的边即可达到目的。书写规则如下:
A→A:标定权值是0
若A→B没有路径可以到达,标定权值为0
若A→C有路径可以到达,根据建模需要标定权值
这样,我们在手动书写时,仅需要写出非0边的权重即可,每条边只需要书写一次,书写方式如下:

W=zeros(11);
W(1,2)=2;
W(1,4)=1;
W(1,3)=8;
W(2,3)=6;
W(2,5)=1;
W(3,4)=7;
W(3,5)=5;
W(3,6)=1;
W(3,7)=2;
W(4,7)=9;
W(5,6)=3;
W(5,8)=2;
W(5,9)=9;
W(6,7)=4;
W(6,9)=6;
W(7,9)=3;
W(7,10)=1;
W(8,9)=7;
W(8,11)=8;
W(9,10)=1;
W(9,11)=2;
W(10,11)=4;

由于本例中为无向图,因此生成的矩阵总满足W(i,j)=W(j,i),所以利用以下代码书写另一半:

n=size(W,1);
for i=1:n
    for j=i:n
        W(j,i)=W(i,j);%次对角线分隔的下三角部分根据上三角部分对称
    end
end
G=graph(W,'upper');%根据带权邻接矩阵生成无向图
plot(G,'EdgeLabel',G.Edges.Weight)
title('标定权重的无向图')

自动绘图效果如下:
标定权重的无向图
带权邻接矩阵W如下:
带权邻接矩阵
(如果要将平时我们认为的不能到达的路径之间权重设定为Inf也很容易,不过在Matlab内置的函数shortestpath中,认为权重0即不设路径)

求两点最短路径

格式:[path,distance]=shortestpath(G,1,6)
path返回的是路径经过的点,distance是该路径的长度

例如在工作区输入:

>>[path,distance]=shortestpath(G,1,6)

显示如下:
在这里插入图片描述
对照我们绘制的无向图也很容易手动验证,最短路径即1→2→5→6,最短路径的距离=2+1+3=6。

有向图(Digraph)

生成带权邻接矩阵

有向图示例如下:
有向图示例
创建一个数组,每一列依次保存起始点,出发点,以及带权。按照和无向图同样的方法对每条边书写带权:

W=[1 2 10;
   1 4 10;
   1 8 1;
   2 3 10;
   2 7 1;
   3 4 10;
   3 6 1;
   4 5 1;
   5 6 12;
   5 8 12;
   6 7 12;
   7 8 12;];

用类似的方法生成有向图如下:

startpoints=W(:,1);%起始点集合
endpoints=W(:,2);%结束点集合
weights=W(:,3);%对应起始点和结束点的边权重
G=digraph(startpoints,endpoints,weights);%生成有向图
plot(G,'EdgeLabel',weights,'layout','force','Edgecolor','red')%画出有向图

效果如下:
在这里插入图片描述

求最短路径

在工作区求取最短路径格式如下:

格式:>> [path,distance]=shortestpath(G,s,t)

得到的结果如下:
结果
在此需要说明的和无向图的区别是,在这里我们只有起始点的点数比终点点数小才有路径,否则没有,因此如果按照如下条件调用,则会得到空集,利用这一个特点可以在程序中增加条件加以排除。
(if distance==Inf 或 if path==[])

>> [path,distance]=shortestpath(G,8,2)

在这里插入图片描述
希望本文对您有帮助,谢谢阅读

  • 70
    点赞
  • 366
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
好的,我可以帮您回答这个问题。 首先,我们需要了解一下 Dijkstra 算法。Dijkstra 算法用于解决带权有向中单源最短路径问题,即从一个源点发,到其他所有点的最短路径。 算法步骤如下: 1. 初始化:将源点加入已访问集合,其余点加入未访问集合,并将源点到各个点的距离初始化为无穷大。 2. 选取距离最短的点:从未访问集合中选取距离源点最近的点,并将其加入已访问集合。 3. 更新距离:更新源点到未访问集合中的点的距离。如果通过当前已访问的点到达该点的距离比源点直接到该点的距离更短,则更新该点的距离。 4. 重复执行第2步和第3步,直到所有点都被加入已访问集合。 现在,我们来看一下使用 C 语言实现 Dijkstra 算法的代码: ```c #include <stdio.h> #define MAX 100 // 定义最大顶点数 #define INF 0x3f3f3f3f // 定义无穷大 int graph[MAX][MAX]; // 有向邻接矩阵 int dist[MAX]; // 存储源点到各个顶点的最短距离 int visited[MAX]; // 标记顶点是否已经访问 void Dijkstra(int start, int n) { // 初始化 for (int i = 0; i < n; i++) { visited[i] = 0; dist[i] = graph[start][i]; } visited[start] = 1; dist[start] = 0; // 进行 n-1 次迭代 for (int i = 0; i < n-1; i++) { int min_dist = INF; int min_index = -1; // 选取距离最短的点 for (int j = 0; j < n; j++) { if (!visited[j] && dist[j] < min_dist) { min_dist = dist[j]; min_index = j; } } if (min_index == -1) { break; } visited[min_index] = 1; // 更新距离 for (int j = 0; j < n; j++) { if (!visited[j] && graph[min_index][j] != INF && dist[min_index] + graph[min_index][j] < dist[j]) { dist[j] = dist[min_index] + graph[min_index][j]; } } } } int main() { int n, start; printf("请输入顶点数:"); scanf("%d", &n); printf("请输入邻接矩阵:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { scanf("%d", &graph[i][j]); if (graph[i][j] == -1) { graph[i][j] = INF; } } } printf("请输入起点编号:"); scanf("%d", &start); Dijkstra(start, n); printf("源点到各个顶点的最短距离为:\n"); for (int i = 0; i < n; i++) { printf("%d ", dist[i]); } printf("\n"); return 0; } ``` 在这个代码中,我们输入了有向邻接矩阵,并将 -1 视为无穷大。然后,我们输入起点编号,调用 Dijkstra 函数计算源点到各个顶点的最短距离,最后输结果。 希望能对您有所帮助!
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非线性光学元件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值