数学建模实战:从网络优化到MATLAB实现Dijkstra最短路径算法

发布时间:2026/8/29 16:44:00
数学建模实战:从网络优化到MATLAB实现Dijkstra最短路径算法 1. 项目概述从实际问题到图论模型搞数学建模的朋友对“图论”这个词肯定不陌生。每次看到赛题里涉及到网络、路径、关系优化心里大概就有数了得请出图论这位老朋友了。但说实话很多刚开始接触的同学一看到“图论”两个字再翻翻教材里那些抽象的定义和公式头就大了。感觉它离解决实际问题很远像是一门纯理论的数学课。我最初也是这么觉得的直到在一次比赛中我们遇到了一个典型的“最短路径配送”问题。题目给了一张城市道路网上面标了各个路口之间的距离要求我们规划出从中心仓库到十几个分散配送点的最优路线使得总运输成本最低。那时候我们团队的第一反应是穷举或者动态规划但稍微一算复杂度就高得吓人。后来在指导老师的点拨下我们意识到这整个道路网不就是一张“图”吗路口是“点”道路是“边”距离就是“权重”。那一刻我才真正开窍原来图论不是飘在天上的理论它就是为描述和解决这类网络结构问题而生的强大工具包。所以这个“数学建模4——图论1”系列我不想一上来就堆概念。我想从一个建模者的视角跟你聊聊怎么把一个个活生生的赛题翻译成图论的语言。我们会重点放在最实用、最高频的“最短路径”问题上并且手把手带你用MATLAB这个建模利器来实现经典的Dijkstra算法。你会发现那些看似复杂的算法一旦和具体的应用场景结合并且有代码落地理解起来会顺畅很多。无论你是正在备战比赛的学生还是工作中需要处理网络优化问题的工程师这篇内容都能给你提供一套从问题识别到代码实现的完整思路。2. 图论基础与建模思维转换2.1 什么是图从生活场景到数学抽象我们首先得统一一下“图”在这里指的是什么。它可不是我们平常说的柱状图、折线图。在图论里图Graph是由顶点Vertex和连接顶点的边Edge组成的集合。你可以把它想象成一张关系网。举个例子社交网络每个人是一个顶点如果两个人是好友那就在他们之间连一条边。这就构成了一张“社交图”。交通网络每个车站、路口是一个顶点连接它们的公路、铁路、航线就是边。知识图谱每个实体如“牛顿”、“万有引力定律”是顶点实体之间的关系如“提出”就是边。在数学建模中我们面对的问题描述往往是文字、表格或示意图。第一步也是最关键的一步就是完成从“自然语言描述”到“图论模型”的转换。这个过程我称之为“建模思维转换”。转换的核心在于识别“实体”和“关系”识别顶点问题中那些独立的、离散的“对象”或“位置”通常就是顶点。比如城市、路口、人物、任务状态、网络节点。识别边顶点之间存在的某种“联系”、“路径”或“交互”就是边。比如城市间的道路、人物间的通信、任务间的先后顺序。定义权重边是否有“代价”比如距离、时间、成本、流量、概率。如果有这个值就是该边的权重。带权重的图称为加权图这是我们处理优化问题如最短路径的基础。注意很多初学者容易混淆“图”和“地图”。图论中的边不一定代表物理连接它可以表示任何抽象关系比如依赖关系、顺序关系。理解这一点才能用图论去解决像工序调度、项目排序这类非空间问题。2.2 图的计算机表示邻接矩阵与邻接表模型建好了怎么让计算机理解呢主要有两种主流的数据结构邻接矩阵和邻接表。选择哪一种直接影响到后续算法的效率和实现的方便程度。邻接矩阵Adjacency Matrix用一个n x n的二维数组矩阵来表示一个具有n个顶点的图。如果顶点i到顶点j有一条边那么矩阵中第i行第j列的元素A(i, j)就存储这条边的信息对于无权图通常用1表示有边0表示无边对于加权图则存储权重值。优点非常直观检查任意两个顶点间是否有边、边的权重是多少速度极快O(1)时间复杂度。缺点非常占用空间。对于一个有n个顶点的图无论有多少条边都需要n^2的存储空间。对于边数远小于n^2的稀疏图比如社交网络一个人不可能认识所有人这种浪费是巨大的。邻接表Adjacency List为每一个顶点维护一个列表记录所有与它直接相连的顶点及边的权重。优点空间利用率高存储稀疏图时优势明显。特别适合需要频繁遍历某个顶点的所有邻居的算法如BFS、DFS。缺点查询任意两个特定顶点间是否有边效率较低需要遍历其中一个顶点的列表。在数学建模特别是使用MATLAB进行原型快速开发时邻接矩阵由于其直观性和与矩阵运算的良好契合度往往是首选。MATLAB对矩阵操作进行了深度优化使用邻接矩阵编写算法代码通常更简洁、更易于理解和调试。除非处理顶点规模极大上万且非常稀疏的图否则邻接矩阵在建模竞赛和一般性研究中完全够用。2.3 知识图谱与邻接矩阵的关系最近“知识图谱”很热它和图论里的“图”是什么关系你可以把知识图谱理解为一种特殊的大规模、带标签、带属性的图。顶点代表实体如“姚明”、“篮球”拥有丰富的属性身高、项目。边代表关系如“从事”、“属于”也拥有类型和可能的权重。邻接矩阵在知识图谱中同样可以作为一种表示方法例如用一个巨大的稀疏矩阵来表示实体间的特定关系如“是队友”关系矩阵。但知识图谱更常用RDF三元组主语-谓语-宾语或属性图数据库来存储因为它们能更好地处理复杂的属性和多种关系类型。不过当我们需要对知识图谱进行某些全局的、基于图结构的分析如计算实体重要性、发现潜在关联时将其转化为邻接矩阵形式再利用图论算法进行计算是一个非常经典的思路。3. 最短路径问题与Dijkstra算法核心解析3.1 问题定义什么是最短路径最短路径问题是图论中最经典、应用最广泛的问题之一。顾名思义就是在加权图中寻找两个顶点之间总权重最小的路径。这里的“最短”是广义的权重可以是距离、时间、费用等任何需要最小化的成本。关键点路径一系列顶点和边的交替序列其中边连接相邻的顶点且顶点不重复简单路径。路径长度/成本路径上所有边的权重之和。目标找到所有可能路径中总成本最小的那一条。应用场景举例导航系统寻找两地间行车时间最短或距离最短的路线。网络路由数据包在互联网中选择延迟最小的传输路径。项目关键路径在工序图中寻找耗时最长的路径可转化为对边权取负等操作。社交网络计算两个人之间的“关系距离”如几度人脉。3.2 Dijkstra算法一步一步找到最优解Dijkstra算法是解决单源最短路径问题的经典算法。所谓“单源”就是从一个指定的起点出发计算它到图中所有其他顶点的最短路径。它的核心思想是“贪心”和“逐步扩张”。我更喜欢把它比喻成“墨水扩散”或者“波前传播”想象在起点滴一滴墨水墨水会沿着边以速度等于边权重的速度扩散。当一个顶点第一次被墨水染到的时间就是起点到该顶点的最短距离。Dijkstra算法就是模拟了这个过程并确保每次“染色”的都是当前未被染色且距离起点最近的顶点。算法的直观步骤初始化创建一个集合S用于存放已经找到最短路径的顶点已染色的顶点。初始时只有起点s在S中且它到自己的距离为0。为所有其他顶点v设置一个“当前已知最短距离”估计值dist[v]起点直接相邻的顶点dist设为边的权重其他顶点设为无穷大Inf。迭代重复以下过程直到所有顶点都进入S a. 从不在S中的顶点里选出dist值最小的那个顶点u。可以证明此时dist[u]就是起点s到u的最终最短距离。为什么因为所有比它更近的路径都已经被探索过了贪心选择性质。 b. 将顶点u加入集合S。 c.松弛操作检查u的所有邻居v且v不在S中。如果通过u到达v比当前已知的路径更短即dist[u] weight(u, v) dist[v]那么就更新dist[v] dist[u] weight(u, v)。同时可以记录下v的前驱顶点是u以便最后回溯出完整路径。结束当所有顶点都进入S算法结束。dist数组存储的就是起点到所有顶点的最短距离。通过前驱顶点信息可以反向构造出到任意目标点的具体路径。实操心得理解“松弛操作”是理解Dijkstra乃至其他最短路径算法的关键。它就像一个“信息更新”过程每当发现一个顶点u的最短距离确定了我们就用它作为“跳板”去尝试更新它邻居们的距离估计。这个操作保证了信息的局部最优能逐步传播为全局最优。3.3 算法局限性与注意事项Dijkstra算法非常强大但它有两个重要的前提权重非负算法要求图中所有边的权重都必须大于或等于0。如果存在负权边Dijkstra算法可能会得出错误结果因为它基于“当前最短即全局最短”的贪心假设负权边会破坏这个假设。对于含负权边的问题需要使用Bellman-Ford算法。有向/无向图Dijkstra算法同样适用于有向图。在构建邻接矩阵时对于有向图A(i, j)代表从i到j的有向边对于无向图A(i, j)和A(j, i)应设为相同的值。常见误区很多同学在手动演算时容易在“选择下一个顶点”和“更新距离”的顺序上出错。一定要牢记先选出当前距离最小的未处理顶点将其标记为已处理然后再用这个顶点去更新其邻居的距离。这个顺序不能颠倒否则可能导致用“未最终确定”的距离去更新其他点引发错误。4. 在MATLAB中实现Dijkstra算法理论说再多不如一行代码。下面我们就用MATLAB从构建邻接矩阵开始完整实现Dijkstra算法并可视化结果。我会详细解释每一段代码的意图。4.1 构建图的邻接矩阵我们首先需要根据问题数据构建邻接矩阵。假设我们有一个6个顶点的无向加权图顶点间连接关系如下格式顶点i 顶点j 权重1, 2, 7 1, 3, 9 1, 6, 14 2, 3, 10 2, 4, 15 3, 4, 11 3, 6, 2 4, 5, 6 5, 6, 9在MATLAB中我们可以这样构建%% 1. 定义顶点数和初始化邻接矩阵 n 6; % 顶点数量 % 初始化一个 n x n 的矩阵用无穷大(Inf)表示两点间没有直接边 A inf(n); % 将对角线设为0自己到自己的距离为0 for i 1:n A(i, i) 0; end %% 2. 根据边列表填充邻接矩阵 % 定义边列表 [起点, 终点, 权重] edges [1, 2, 7; 1, 3, 9; 1, 6, 14; 2, 3, 10; 2, 4, 15; 3, 4, 11; 3, 6, 2; 4, 5, 6; 5, 6, 9]; % 因为是无向图所以边是双向的 for i 1:size(edges, 1) u edges(i, 1); v edges(i, 2); w edges(i, 3); A(u, v) w; A(v, u) w; % 无向图对称赋值 end disp(邻接矩阵 A:); disp(A);运行这段代码你会得到一个6x6的矩阵。Inf表示没有直接连接数字表示权重对角线是0。这就是我们图在计算机中的“地图”。4.2 Dijkstra算法函数实现接下来我们编写一个通用的Dijkstra算法函数。这个函数输入邻接矩阵A和起点start返回最短距离数组dist和前驱节点数组prev。function [dist, prev] dijkstra(A, start) % DIJKSTRA 使用Dijkstra算法计算单源最短路径 % 输入 % A - n x n 的邻接矩阵A(i,j)为顶点i到j的边权无边则为Inf % start - 起点编号 % 输出 % dist - 1 x n 向量dist(i)为起点到顶点i的最短距离 % prev - 1 x n 向量prev(i)为起点到顶点i的最短路径上i的前一个顶点 n size(A, 1); % 顶点数 dist inf(1, n); % 初始化距离为无穷大 prev zeros(1, n); % 前驱节点0表示无前驱起点或不可达 visited false(1, n); % 标记顶点是否已找到最短路径 dist(start) 0; % 起点到自己的距离为0 for i 1:n % 步骤1: 从未访问顶点中找出当前距离最小的顶点u % 这里用一个简单循环实现对于大规模图可用优先队列优化 minDist inf; u -1; for v 1:n if ~visited(v) dist(v) minDist minDist dist(v); u v; end end % 如果所有未访问顶点距离都是无穷大说明剩余顶点不可达提前结束 if u -1 break; end visited(u) true; % 标记u为已访问 % 步骤2: 松弛操作 - 更新u的所有邻居的距离 for v 1:n % 如果v未访问且u到v有边 if ~visited(v) A(u, v) inf alt dist(u) A(u, v); % 通过u到v的新距离 if alt dist(v) % 如果新距离更短 dist(v) alt; % 更新距离 prev(v) u; % 记录前驱 end end end end end代码解读与注意事项visited数组这是算法中集合S的实现用布尔数组标记顶点状态。寻找最小dist的循环这是算法效率的关键。上述代码用了简单的线性扫描时间复杂度是 O(n)。在一个有n个顶点的图中主循环n次每次扫描n个点所以总复杂度是O(n^2)。这对于顶点数不多几百上千的建模问题完全足够。如果处理大规模稀疏图应该用最小堆优先队列来优化这一步可将复杂度降至 O((ne) log n)其中e是边数。MATLAB中可以使用min函数配合逻辑索引进行一定优化但实现完整的优先队列稍复杂。松弛操作if alt dist(v)这个判断是核心。它确保了距离估计只会被更优的值更新。前驱数组prev它像一个“路标”记录了到达每个顶点的最佳上一站。通过它我们可以从终点回溯到起点还原出完整的最短路径。4.3 路径回溯与结果展示计算出了dist和prev我们还需要一个函数来根据prev回溯出从起点到任意终点的具体路径。function path getPath(prev, start, target) % GETPATH 根据前驱节点数组回溯出最短路径 % 输入 % prev - dijkstra函数输出的前驱数组 % start - 起点编号 % target - 终点编号 % 输出 % path - 从起点到终点的路径顶点序列如果不可达则为空数组 if prev(target) 0 target ~ start % 终点没有前驱且不是起点说明不可达 path []; return; end path []; u target; % 从终点反向追溯到起点 while u ~ 0 path [u, path]; % 将当前节点加到路径开头 u prev(u); % 移动到前一个节点 end % 检查路径是否以起点开始应对某些特殊情况 if ~isempty(path) path(1) ~ start path []; end end现在让我们运行完整的流程%% 主程序计算并展示从顶点1到所有顶点的最短路径 start_node 1; [distances, predecessors] dijkstra(A, start_node); fprintf(从顶点 %d 出发的最短路径结果\n, start_node); fprintf(顶点\t最短距离\t路径\n); for target 1:n path getPath(predecessors, start_node, target); if isempty(path) fprintf(%d\t不可达\t\t-\n, target); else fprintf(%d\t%.2f\t\t%s\n, target, distances(target), num2str(path)); end end运行后你会看到类似下面的输出从顶点 1 出发的最短路径结果 顶点 最短距离 路径 1 0.00 1 2 7.00 1 2 3 9.00 1 3 4 20.00 1 3 4 5 20.00 1 3 6 5 6 11.00 1 3 6这清晰地告诉我们从顶点1到顶点5的最短距离是20路径是 1 - 3 - 6 - 5。注意到顶点4的最短路径是 1-3-4距离20而不是直接 1-2-4距离22。这正是算法计算出的最优解。4.4 可视化让结果一目了然对于建模论文或报告将图和最短路径可视化能极大提升表现力。我们可以用MATLAB的绘图功能简单实现。%% 可视化图与最短路径以到顶点5为例 target_node 5; shortest_path getPath(predecessors, start_node, target_node); % 为顶点定义一些简单的坐标这里为了演示手动定义。复杂图可用其他布局算法 % 这只是一个示例布局实际中可能需要根据图结构调整 pos [0, 0; % 1 2, 3; % 2 1, 1.5; % 3 3, 2; % 4 4, 0; % 5 2, 0]; % 6 figure(Position, [100, 100, 800, 600]); hold on; grid on; box on; title(sprintf(图结构及从顶点%d到顶点%d的最短路径, start_node, target_node)); % 1. 绘制所有边灰色细线 for i 1:n for j i1:n % 无向图只画一半避免重复 if A(i, j) inf plot([pos(i,1), pos(j,1)], [pos(i,2), pos(j,2)], ... Color, [0.7, 0.7, 0.7], LineWidth, 1, LineStyle, --); % 在边中间标注权重 midPoint (pos(i,:) pos(j,:)) / 2; text(midPoint(1), midPoint(2), sprintf(%.0f, A(i,j)), ... HorizontalAlignment, center, BackgroundColor, white); end end end % 2. 高亮显示最短路径上的边红色粗线 for k 1:length(shortest_path)-1 i shortest_path(k); j shortest_path(k1); plot([pos(i,1), pos(j,1)], [pos(i,2), pos(j,2)], ... r-, LineWidth, 3); end % 3. 绘制所有顶点 scatter(pos(:,1), pos(:,2), 200, b, filled); % 蓝色大圆点 % 在顶点旁标注编号 for i 1:n text(pos(i,1), pos(i,2)0.15, sprintf(%d, i), ... FontSize, 12, FontWeight, bold, HorizontalAlignment, center); end % 4. 高亮起点和终点 scatter(pos(start_node,1), pos(start_node,2), 300, g, ^, LineWidth, 2); % 绿色三角起点 scatter(pos(target_node,1), pos(target_node,2), 300, m, s, LineWidth, 2); % 洋红色方块终点 xlabel(X); ylabel(Y); axis equal; % 保持坐标轴比例相同 hold off;这段代码会生成一张图灰色虚线表示所有边旁边标有权重红色粗线高亮显示了从起点1到终点5的最短路径1-3-6-5绿色三角形是起点洋红色方块是终点。这样的图表放在论文里评委一眼就能看懂你的模型结果。5. 实战进阶与常见问题排查掌握了基础实现我们来看看如何应对更复杂的情况和那些容易踩的坑。5.1 处理大规模图与性能优化我们之前实现的O(n^2)算法对于n1000的稠密图在现代计算机上也能很快完成。但如果n达到10万、100万这个复杂度就不行了。这时需要优化使用邻接表存储稀疏图对于边数e远小于n^2的图用邻接矩阵存储和遍历是巨大的浪费。应改用邻接表。在MATLAB中可以用元胞数组实现adjList{i}存储一个[邻居节点, 权重]的矩阵。使用优先队列最小堆Dijkstra算法中寻找未访问节点中dist最小的顶点是性能瓶颈。用优先队列可以将这一步的复杂度从 O(n) 降到 O(log n)。MATLAB没有内置的堆数据结构但可以自己实现一个简单的二叉堆或者利用min函数和逻辑索引进行部分优化但效果不如真正的堆。考虑使用MATLAB内置函数或工具箱MATLAB的graph和digraph对象需要 Bioinformatics Toolbox 或 MATLAB R2015b内置了强大的图论算法。创建图对象后直接调用shortestpath或distances函数即可它们通常经过高度优化。% 使用 graph 对象 G graph(A); % A可以是稀疏矩阵 [path, d] shortestpath(G, start_node, target_node); all_dist distances(G, start_node); % 计算到所有节点的距离在数学建模竞赛中如果允许使用工具箱强烈推荐直接调用内置函数它们高效、稳定且代码简洁。自己实现算法更多是为了理解和应对特殊需求。5.2 常见错误与调试技巧在实现和应用Dijkstra算法时以下几个错误非常常见负权边这是最致命的错误。如果你的图中有负权边比如某些路径代表“收益”而非“成本”Dijkstra算法会失效。务必在算法开始前检查邻接矩阵。if any(A(A inf) 0) error(图包含负权边Dijkstra算法不适用请考虑使用Bellman-Ford算法。); end自环与平行边自环自己到自己的边除非权重为负否则不影响结果但通常应剔除A(i,i)0。平行边两点间多条边在构建邻接矩阵时通常只保留权重最小的一条作为直接连接因为最短路径显然会选择最短的那条边。无穷大Inf的处理在MATLAB中Inf参与比较和运算是安全的。但在某些语言中需要用一个极大的数如1e9代替。在更新距离时要确保Inf w仍然等于Inf在MATLAB中成立。路径回溯错误getPath函数在遇到不可达节点或起点终点相同的情况时可能出错。确保你的回溯逻辑包含边界条件检查如上面代码所示。邻接矩阵初始化错误最常见的错误是忘记将对角线设为0或者忘记将无连接设为Inf。一个检查方法是对于无向图邻接矩阵应该是对称的A A对于有向图则不一定。调试小技巧对于小型图最好的调试方式就是“人肉模拟”。把你的图画在纸上按照你的代码逻辑一步一步手动执行算法记录每一步的dist数组、visited数组和prev数组的变化然后与程序输出对比。这是定位逻辑错误最有效的方法。5.3 从最短路径到建模应用拓展Dijkstra算法解决的是单源最短路径。在建模中问题可能更复杂多源最短路径需要计算所有顶点对之间的最短距离。可以对每个顶点作为起点运行一次Dijkstra算法复杂度 O(n * n^2) O(n^3)但对于稠密图Floyd-Warshall算法动态规划思想O(n^3)的代码更简洁。K最短路径不仅需要最短路径还需要第二短、第三短的路径。这需要使用更复杂的算法如Yens Algorithm。动态网络边的权重随时间变化如交通拥堵。这需要将时间维度纳入模型可能使用时间依赖的最短路径算法。带约束的最短路径在寻找最短路径的同时还要满足其他约束如总费用不超过预算、必须经过某些点等。这通常可以转化为约束规划或动态规划问题。一个建模技巧很多看似不是“路径”的问题可以通过巧妙的构图转化为最短路径问题。例如状态转移问题将每个状态看作一个顶点状态间的合法转移看作带权边求初始状态到目标状态的最小代价转移过程。项目时间规划在关键路径法CPM中求最早完成时间等价于在图中求最长路径可以通过对边权取负转化为求最短路径问题需使用能处理负权的算法如Bellman-Ford。6. MATLAB相关工具与技巧拾遗在围绕图论进行数学建模时熟练使用MATLAB能事半功倍。这里补充几个经常被问到的技巧和常见问题。6.1 高效处理图数据的技巧使用稀疏矩阵当图的规模很大且稀疏时用sparse函数创建稀疏邻接矩阵能极大节省内存和计算时间。% 从边列表创建稀疏矩阵 [rows, cols, weights] find(tril(A, -1)); % 获取无向图下三角部分的边避免重复 % 假设我们有 edges 矩阵 [u, v, w] u edges(:,1); v edges(:,2); w edges(:,3); n max(max(u), max(v)); % 确定顶点数 A_sparse sparse([u; v], [v; u], [w; w], n, n); % 创建对称的稀疏矩阵 % 使用 A_sparse 作为 graph 对象的输入 G graph(A_sparse);使用稀疏矩阵后很多矩阵运算会自动采用稀疏算法速度更快。graph/digraph对象是利器如前所述这是MATLAB处理图论问题的现代方式。它封装了数据结构和大量算法并且绘图功能强大。G graph(A); % 从邻接矩阵创建无向图 % 或者从边列表创建 G graph(edges(:,1), edges(:,2), edges(:,3)); plot(G, EdgeLabel, G.Edges.Weight, NodeLabel, 1:numnodes(G), LineWidth, 2); % 自动计算最短路径 [path, d] shortestpath(G, 1, 5); highlight(p, path, EdgeColor, r, LineWidth, 3); % 高亮路径6.2 数据分析与结果验证计算完最短路径后我们通常需要做进一步分析或验证。ttest和ttest2的区分虽然这不是图论直接相关的但在建模中分析不同路径方案的效果时可能会用到。ttest单样本t检验。用于检验一组数据的均值是否等于某个假设值。例如你模拟了10次采用最短路径的运输时间想检验平均时间是否小于某个标准值。[h,p] ttest(transport_times, target_time, Tail, left); % 左尾检验均值是否小于target_timettest2双样本t检验。用于检验两组独立数据的均值是否有显著差异。例如你比较采用最短路径组A和随机路径组B的运输成本看是否有显著差异。[h,p] ttest2(cost_groupA, cost_groupB);关键区别在于ttest比较一组数据和一个常数ttest2比较两组数据。结果的可视化与导出除了用plot画网络图还可以用bar、histogram来展示不同路径的成本分布。要将高质量的图放入论文建议使用exportgraphics或saveas函数导出为矢量格式如PDF、EPS。% 导出为PDF质量高 exportgraphics(gcf, shortest_path_result.pdf, ContentType, vector); % 或者导出为高分辨率PNG saveas(gcf, network_plot.png);6.3 避坑指南那些年我踩过的MATLAB的“坑”下标索引从1开始这是MATLAB与C、Python等语言最大的不同之一。在实现算法时循环for i 1:n是标准写法。如果你从其他语言转过来务必时刻牢记。矩阵运算与循环MATLAB的矩阵运算远快于循环。在可能的情况下尽量将操作向量化。例如在Dijkstra算法的松弛步骤中我们用了循环遍历所有顶点来检查邻居。如果图很稠密用矩阵操作可能更快但对于稀疏图和清晰的逻辑循环的可读性更好。在建模竞赛中清晰正确优先于微小的性能优化。Inf和NaNInf表示无穷大在最短路径初始化中很有用。NaN表示“不是数字”任何包含NaN的运算结果通常也是NaN。要小心区分初始化距离数组应用inf(1,n)而不是nan(1,n)。函数未定义错误提示“函数或变量 ‘xxx’ 无法识别”通常有三个原因一是拼写错误二是该函数属于某个工具箱但你没有安装三是文件路径不对当前工作目录下没有这个函数文件。确保你的自定义函数如dijkstra.m保存在MATLAB的当前文件夹或搜索路径中。MATLAB版本兼容性graph对象在较新的版本R2015b中才引入。如果你在旧版本或不确定比赛环境使用邻接矩阵和自定义函数是更稳妥的选择。提交论文时如果附代码最好注明所需的MATLAB版本或工具箱。最后关于网络上搜索到的一些非常具体的MATLAB问题如“如何截断横坐标”、“1e100如何表示”、“movefile函数用法”等这些问题通常有非常明确的答案建议查阅MATLAB官方文档doc命令或在专注于编程的社区搜索。在图论建模的语境下我们的核心是把握住“问题 - 图模型 - 算法选择 - MATLAB实现 - 结果分析”这条主线把工具用对地方让算法解决实际问题这才是数学建模的精髓。当你通过一个具体的路径规划问题亲手实现了Dijkstra算法并得到正确结果时你对图论的理解会比读十篇理论文章都要深刻。