1 问题分析和任务定义
1.1 问题描述和要求
【问题描述】 赛事系统为参赛者提供赛地的校园导游程序。为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询,即查询任意两个目的地(建筑物)之间的一条最短的简单路径。
【基本要求】赛地目的地查询,需提供目的地(建筑物)名称、代号、简介等信息;最短路径的输出需包含途经地及最短路径值。
1.2 问题分析
这是一个图论问题,校园内道路一般是双向通行的,所以这是一个无向图。下面先对图的基本概念进行介绍:
图由节点(顶点)和边组成,用 G=(V,E) 表示,其中 V 表示节点的集合,E 表示边的集合。边可以是有向的,也可以是无向的。图可以分为有向图和无向图。
2. 图的存储
图的存储方式有两种:邻接矩阵和邻接表。邻接矩阵是一个二维数组,其中矩阵中的每个元素表示两个节点之间的边的权重;邻接表是由链表构成的数组,每个节点包含一个指向与其相邻的节点的指针。
3. 图的遍历
图的遍历有两种方式:深度优先搜索(DFS)和广度优先搜索(BFS)。DFS 从一个起点开始,沿着一条路径尽可能深地访问节点,直到无法继续为止,然后回退到上一个节点,继续访问其他路径。BFS 从一个起点开始,先访问所有与起点相邻的节点,然后访问与这些节点相邻的节点,以此类推。
4. 最短路径
最短路径算法用于计算两个节点之间的最短路径,其中最著名的算法是 Dijkstra 算法和 Bellman-Ford 算法。Dijkstra 算法用于计算有向无环图(DAG)中的最短路径,而 Bellman-Ford 算法可以处理带有负权边的图。
对于图的存储结构而言,图中各个景点的存储结构有邻接表和邻接矩阵两种存储结构,考虑到顶点个数少于50个,所以邻接表和邻接矩阵的复杂度相同。本题中选择使用邻接矩阵来表示图。
任务中要求求解出图中景点的问路查询,即为给定两个源点,求解出两个顶点之间的最短路径。校园中道路没有负权边,可以不使用Bellman-Ford 算法。Dijkstra算法是求单元最短路径的算法,即是求某个顶点到其余各顶点的最短路径。而Floyd算法是动态规划算法,求任意两个顶点之间的最短路径。,floyd算法解决了所有顶点到所有顶点的最短路径问题。相比之下,floyd算法的时间复杂度为O(n ^ 3),空间复杂度是O(n ^ 2),算法优点是,可以算出任意两点间的最短路径,代码编写也较简单。缺点是,时间复杂度比较高,不太适合大量数据的计算。对于校园导航,景点很少,所以使用floyd算法
数据结构的选择
此问题需要用到邻接矩阵,因此采用了数组。
概述
本实验的编程语言采用 Java ,主要是求解通过Floyd算法求解图论问题
Graph类和Vertex类
结点信息的数据结构:类——View 用于存储各个结点的详细信息,如景点编号、名称和景点介绍等class Graph{//地图
Vertex vex[]=new Vertex[20];
int dis[][]=new int[20][20];
}
class Vertex{//景点
String name;
String info;
public Vertex() {
}
public Vertex(String name,String info) {
this.name=name;
this.info=info;
}
}
GraphMain类
这部分主要是学校地图的打印,程序中用到的校园平面图可以用制表符绘制出来,虽然过程繁琐,但是较为简单方便。
PrintPath类
这部分主要是存储了各个顶点之间的距离,并使用了Floyd算法对最短路径进行求解。
算法步骤:
弗洛伊德算法选取某个节点k作为i到j需要经过的中间节点,通过比较d(i,k)+d(k,j)和现有d(i,j)的大小,将较小值更新为路径长度,对k节点的选取进行遍历,以得到在经过所有节点时i到j的最短路径长度,通过不断加入中间点的方式更新最短路径。同时在path数组中存储i到j所经过的中间节点k,用于最后递归调用输出路径结果。
其中matrix[i,j]表示i到j的最短距离,k是穷举i到j之间可能经过的中间点,当中间点为k时,对整个矩阵即从i到j的路径长度进行更新,对所有可能经过的中间点进行遍历以得到全局最优的最短路径。算法的单个执行将找到所有顶点对之间的最短路径长度,与迪杰斯特阿拉算法的计算目标有一些差异,迪杰斯特拉计算的是单源最短路径,而弗洛伊德计算的是多源最短路径,其时间复杂度为O(n³)。虽然它不返回路径本身的细节,但是可以通过对算法的简单修改来重建路径,我们利用这个思想,通过递归的方式访问每条路径经过的中间节点,对最终的路径进行输出。
算法中的三层for循环,第一层循环设置中间点k,第二层循环设置起始点i,第三层循环设置结束点j。
下面是示意图图例