1、景区旅游信息管理系统校园旅游信息管理系统1.1项目需求分析在旅游景区,经常会遇到游客打听从一个景点到另一个景点的最短路径和最短距离,这类游客不喜欢按照导游图的线路来游览,而是挑选自己感兴趣的景点游览。为于帮助这类游客信息查询,就需要计算出所有景点之间最短路径和最短距离。算法采用迪杰斯特拉算法或弗洛伊德算法均可.建立一个景区旅游信息管理系统,实现的主要功能包括制订旅游景点导游线路策略和制订景区道路铺设策略。任务中景点分布是一个无向带权连通图,图中边的权值是景点之间的距离。1)景区旅游信息管理系统中制订旅游景点导游线路策略,首先通过遍历景点,给出一个入口景点,建立一个导游线路图,导游线路图用有向图
2、表示.遍历采用深度优先策略,这也比较符合游客心理。 (2)为了使导游线路图能够优化,可通过拓朴排序判断图中有无回路,若有回路,则打印输出回路中的景点,供人工优化。 (3)在导游线路图中,还为一些不愿按线路走的游客提供信息服务,比如从一个景点到另一个景点的最短路径和最短距离。在本线路图中将输出任意景点间的最短路径和最短距离。 (4)在景区建设中,道路建设是其中一个重要内容.道路建设首先要保证能连通所有景点,但又要花最小的代价,可以通过求最小生成树来解决这个问题。本任务中假设修建道路的代价只与它的里程相关。因此归纳起来,本任务有如下功能模块:创建景区景点分布图;输出景区景点分布图(邻接矩阵)输出导
3、游线路图;判断导游线路图有无回路;求两个景点间的最短路径和最短距离;输出道路修建规划图.主程序用菜单选项供用户选择功能模块。1.2项目设计流程 1。2。1项目总体框架 1。2。2项目数据结构ifndef SUCCESS /标志位成功#define SUCCESS 1endif#ifndef FAILURE /标志位失败define FAILURE 0endififndef INF /标志位无穷define INF 0x3f3fffffendififndef MAXNUM #define MAXNUM 20endiftypedef bool STATUS; /定义函数状态数据类型typedef
4、char VERTEXTYPEMAXNUM11; /定义顶点向量数据类型typedef int ADJMATRIXMAXNUMMAXNUM; /定义邻接矩阵数据类型typedef struct GRAPH /定义图数据类型 VERTEXTYPE Vexs; /图的顶点向量 ADJMATRIX Arcs; /图的邻接矩阵 int VexNum; /图的当前顶点 int ArcNum; /图的当前弧*PGRAPH; /定义图的指针数据类型typedef struct CLOSEDGE /定义辅助数组数据类型 VERTEXTYPE Vexs; /图的顶点向量 int LowcostMAXNUM; /
5、*PCLOSEDGE; /定义辅助数组指针数据类型1.2。3项目模块设计创建景区景点分布图一.邻接矩阵 (Adjacency Matrix)(二维数组表示法)在图的邻接矩阵表示中,有一个记录各个顶点信息的顶点表,还有一个表示各个顶点之间关系的邻接矩阵。设图 A = (V, E)是一个有 n 个顶点的图, 图的邻接矩阵是一个二维数组 A。edgenn,定义(满足如下条件的n阶矩阵):无向图数组表示法特点:1)无向图邻接矩阵是对称矩阵,同一条边表示了两次;2)顶点v的度:在无向图中等于二维数组对应行(或列)中1的个数;在有向图中, 统计第 i 行 1 的个数可得顶点 i 的出度,统计第 j 列 1
6、 的个数可得顶点 j 的入度。3)判断两顶点v、u是否为邻接点:只需判二维数组对应分量是否为1;4)顶点不变,在图中增加、删除边:只需对二维数组对应分量赋值1或清0;5)设存储顶点的一维数组大小为n(图的顶点数n), G占用存储空间:n+n2;G占用存储空间只与它的顶点数有关,与边数无关;适用于边稠密的图; 流程图:程序:/创建景区景点分布图STATUS CreateGraph(PGRAPH pGraph) printf(”ttt_n”); printf(”ntttt创建景区景点分布图t$n”); printf(”ttt_n); /初始化图的顶点数 printf(”ttt初始化顶点数和弧度数。
7、.。.。.n”); printf(”ttt请输入图的顶点数(=20):”); scanf(”d,pGraphVexNum); /检查 if(pGraphVexNum20) printf(”ttt警告:输入数据错误!!!n”); printf(ttt按任意键回主菜单!!!”); getch(); return FAILURE; /初始化图的弧数 printf(ttt请输入图的弧度数(=20):); scanf(”d”,pGraphArcNum); /检查 if(pGraphArcNum20) printf(”ttt警告:输入数据错误!!n); printf(”ttt按任意键回主菜单!); get
8、ch(); return FAILURE; /初始化图的顶点名称 printf(”ttt-n”); printf(”ttt初始化的顶点名称.。.n”); for(int i=0;ipGraph-VexNum;i+) printf(”ttt请输入第d个顶点名称:”,i+1); scanf(”%s,pGraphVexsi); /初始化图的弧权值为最大值 for(i=0;iVexNum;i+) for(int j=0;jpGraphVexNum;j+) pGraph-Arcsij=INF; /输入弧的信息 printf(”ttt-n); printf(ttt初始化的弧的信息。.。.。n); prin
9、tf(”ttt请输入弧的信息(注:从0开始):n”); for(i=0;iArcsStavEndv=Weight; printf(”ttt创建景区景点分布图成功!!n); printf(ttt按任意键回主菜单!!”); getch(); return SUCCESS;输出景区景点分布图流程图:程序:/输出景区景点分布图STATUS PrintGraph(const PGRAPH pGraph) printf(ttt_n); printf(ntttt显示景区景点分布图t$n”); printf(ttt_nn”); / printf(”t景区景点名称。.。.nt”); for(int i=0;ip
10、GraphVexNum;i+) printf(%st”,pGraph-Vexsi); printf(”nnt景区景点信息。.。n”); for(i=0;iVexNum;j+) if(pGraph-Arcsij=INF) printf(”t); else printf(dt”,pGraphArcsij); printf(”n); printf(t_nt”); printf(”按任意键回主菜单!!”); getch(); return SUCCESS; 输出景区导游线路图图的遍历从图中某一顶点出发访遍图中所有的顶点,且使每个顶点仅被访问一次,这一过程就叫做图的遍历 (Traversing Grap
11、h)。图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组 visited .辅助数组 visited 的初始状态为 0, 在图的遍历过程中, 一旦某一个顶点 i 被访问, 就立即让 visited i 为 1, 防止它被多次访问。两种图的遍历方法:深度优先搜索 DFS (Depth First Search)广度优先搜索 BFS (Breadth First Search)广度优先搜索遍历图(BFS)对连通图,从起始点V到其余各顶点必定存在路径。 其中,V-w1, Vw2
12、, Vw8 的路径长度为1; Vw7, Vw3, V-w5 的路径长度为2; V-w6, Vw4 的路径长度为3从图中的某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到. 若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止.流程图:程序: /输出景区导游线路图(注:广度优先遍历)STATUS TraverseGraph(const PGRAPH pGraph) printf(ttt_n”); printf(ntt
13、t$t输出景区导游线路图t$n”); printf(ttt_nn”); /定义访问标志数组 bool Visit=(bool)malloc(pGraphVexNum*sizeof(bool); /初始化访问标志数组为false for(int i=0;iVexNum)=FAILURE) printf(”ttt警告:创建队列失败!!!n”); printf(ttt按任意键回主菜单!!”); getch(); return FAILURE; /定义访问顶点变量,并初始值为0 int Vertex=0; do if(!VisitVertex) printf(”ttt%s景点.。.。n”,pGraph
14、-VexsVertex); /标志访问过 VisitVertex=true; /遍历与Vertex相连的顶点并进队 for(i=0;ipGraph-VexNum;i+) if(Visiti=false&pGraph-ArcsVertexi!=INF) EnQueue(Queue,i); /出队 DeQueue(&Queue,Vertex); while(QueueLen(Queue); /销毁队列 DestroyQueue(Queue); printf(”ttt按任意键回主菜单!); getch(); return SUCCESS;有向图的拓扑排序何谓“拓扑排序”? 对有向图进行如下操作:假设
15、G=(V,E)是一个具有n个顶点的有向图,V中顶点序列vl,v2,,vn称做一个拓扑序列(Topological Order),当且仅当该顶点序列满足下列条件:若在有向图G中存在从顶点vi到vj的一条路径,则在顶点序列中顶点vi必须排在顶点vj之前。通常,在AOV网中,将所有活动排列成一个拓扑序列的过程叫做拓扑排序(Topological Sort)。在AOV网中不应该出现有向环。因为环的存在意味着某项活动将以自己为先决条件,显然无法形成拓扑序列。判定网中是否存在环的方法:对有向图构造其顶点的拓扑有序序列,若网中所有顶点都出现在它的拓扑有序序列中,则该AOV网中一定不存在环.例如:对于有向图
16、可求得拓扑有序序列: A B C D 或 A C B D 例如, 对学生选课工程图进行拓扑排序, 得到的拓扑有序序列为 C1 , C2 , C3 , C4 , C5 , C6 , C8 , C9 , C7或 C1 , C8 , C9 , C2 , C5 , C3 , C4 , C7 , C6 反之,对于下列有向图 不能求得它的拓扑有序序列。 因为图中存在一个回路 B, C, D 如何进行 ?输入AOV网络.令 n 为顶点个数。 (1)在AOV网络中选一个没有直接前驱的顶点,并输出之; (2)从图中删去该顶点, 同时删去所有它发出的有向边;重复以上步骤,直到全部顶点均已输出,拓扑有序序列形成,拓
17、扑排序完成;或图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了.这时AOV网络中必定存在有向环。在实现拓扑排序的算法中,采用邻接表作为有向图的存储结构,每个顶点设置一个单链表,每个单链表有一个表头结点,在表头结点中增加一个存放顶点入度的域count,这些表头结点构成一个数组。为了避免重复检测入度为0的点,另设一栈存放所有入度为0的点。对于有n个顶点和e条边的有向图而言,for循环中建立入度为0的顶点栈时间为O(n);若在拓扑排序过程中不出现有向环,则每个顶点出栈、入栈和入度减1的操作在while循环语句中均执行e次,因此拓扑排序总的
18、时间花费为O (n+e)。流程图:程序:/有向图的拓扑排序STATUS TopologicalSort(const PGRAPH pGraph) printf(”ttt_n”); printf(nttt$t导游线路图有无回路tn); printf(”ttt_nn”); /定义入度数组,记录每个顶点的入度,初始化为0 int IndegreeMAXNUM=0; /定义桟、并初始化桟 STACK Stack; if(InitStack(Stack,pGraphVexNum)=FAILURE) printf(”ttt警告:创建桟失败!!n”); printf(”ttt按任意键回主菜单!!!); ge
19、tch(); return FAILURE; printf(”ttt计算各顶点的入度.。.n”); for(int j=0;jVexNum;j+) /求各个顶点的入度 for(int i=0;ipGraph-VexNum;i+) if(pGraphArcsij!=INF) Indegreej+; /入度为0的顶点入栈 if(!Indegreej) PushStack(Stack,j); printf(”ttt进行拓扑排序。.。n”); /Count用来指示入度为0的顶点个数 int Count=0,k; while(StackLen(&Stack) /出桟、并访问 PopStack(&Stac
20、k,k); printf(%st,pGraphVexsk); Count+; /对出栈的顶点所指向的顶点减一 ,并且将入度为0的顶点入栈 for(int i=0;ipGraph-VexNum;i+) if(pGraphArcski!=INF) if(!(-Indegreei)) PushStack(&Stack,i); /销毁桟 DestroyStack(Stack); /判断是否是拓扑排序 if(CountVexNum) printf(”ttt结果:导游线路图有回路n); else printf(ttt结果:导游线路图无回路n); printf(”ttt按任意键回主菜单!!”); getch
21、(); return SUCCESS;求两个景点间的最短路径最短路径定义所谓最短路径问题是指:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径似的沿此路径上各边的权值总和(称为路径长度)达到最小.迪杰斯特拉(Dijkstra)算法求单源最短路径由Dijkstra提出的一种按路径长度递增序产生各顶点最短路径的算法.(1)按路径长度递增序产生各顶点最短路径若按长度递增的次序生成从源点s到其它顶点的最短路径,则当前正在生成的最短路径上除终点以外,其余顶点的最短路径均已生成(将源点的最短路径看作是已生成的源点到其自身的长度为0的路径)。(2)具体做法一开始第一组只包括
22、顶点 v 1 ,第二组包括其他所有顶点, v 1 对应的距离值为 0 ,第二组的顶点对应的距离值是这样确定的:若图中有边 是图 G 中的边,则 costij 的值等于边所带的权 ; 若 v i , v j 不是图 G 中的边,则 costij 等于一个很大的数;若 i=j, 则 costij=0 。另外 , 设置三个数组 Sn 、 distn 、 pren 。 S 用以标记那些已经找到最短路径的顶点,若 Si1=1, 则表示已经找到源点到顶点 i 的最短路径 , 若 Si1=0, 则表示从源点到顶点 i 的最短路径尚未求得。 disti1 用来记录源点到顶点 i 的最短路径。 prei1 表示
23、从源点到顶点 i 的最短路径上该点的前趋顶点,若从源点到该顶点无路径,则用 0 作为其前一个顶点序号。流程图:程序:/求两个景点间的最短路径STATUS MinShortPath(const PGRAPH pGraph) printf(”ttt_n”); printf(”nttt$t景点之间的最短路径tn”); printf(ttt_nn); /定义路径矩阵、距离矩阵 ADJMATRIX PathMatrix,DisMatrix; /定义辅助变量 int i,j,k; /初始化路径矩阵、距离矩阵 for(i=0;iVexNum;i+) for(j=0;jpGraphVexNum;j+) DisMatrixij=pGraph-Arcsij; PathMatrixij=1; /求PathMatrix矩阵 for(k=0;kpGraph-VexNum;k+) for(i=0;ipGraphVexNum;i+) for(j=0;jpGraph-VexNum;j+) if(DisMatrix
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1