景区旅游信息管理系统.docx
《景区旅游信息管理系统.docx》由会员分享,可在线阅读,更多相关《景区旅游信息管理系统.docx(32页珍藏版)》请在冰豆网上搜索。
![景区旅游信息管理系统.docx](https://file1.bdocx.com/fileroot1/2022-11/22/715e23ea-e54e-4b25-ba48-4dc3d5046edd/715e23ea-e54e-4b25-ba48-4dc3d5046edd1.gif)
景区旅游信息管理系统
校园旅游信息管理系统
1.1项目需求分析
在旅游景区,经常会遇到游客打听从一个景点到另一个景点的最短路径和最短距离,这类游客不喜欢按照导游图的线路来游览,而是挑选自己感兴趣的景点游览。
为于帮助这类游客信息查询,就需要计算出所有景点之间最短路径和最短距离。
算法采用迪杰斯特拉算法或弗洛伊德算法均可.建立一个景区旅游信息管理系统,实现的主要功能包括制订旅游景点导游线路策略和制订景区道路铺设策略。
任务中景点分布是一个无向带权连通图,图中边的权值是景点之间的距离。
1)景区旅游信息管理系统中制订旅游景点导游线路策略,首先通过遍历景点,给出一个入口景点,建立一个导游线路图,导游线路图用有向图表示.遍历采用深度优先策略,这也比较符合游客心理。
(2)为了使导游线路图能够优化,可通过拓朴排序判断图中有无回路,若有回路,则打印输出回路中的景点,供人工优化。
(3)在导游线路图中,还为一些不愿按线路走的游客提供信息服务,比如从一个景点到另一个景点的最短路径和最短距离。
在本线路图中将输出任意景点间的最短路径和最短距离。
(4)在景区建设中,道路建设是其中一个重要内容.道路建设首先要保证能连通所有景点,但又要花最小的代价,可以通过求最小生成树来解决这个问题。
本任务中假设修建道路的代价只与它的里程相关。
因此归纳起来,本任务有如下功能模块:
创建景区景点分布图;
输出景区景点分布图(邻接矩阵)
输出导游线路图;
判断导游线路图有无回路;
求两个景点间的最短路径和最短距离;
输出道路修建规划图.
主程序用菜单选项供用户选择功能模块。
1.2项目设计流程
1。
2。
1项目总体框架
1。
2。
2项目数据结构
#ifndefSUCCESS//标志位成功
#defineSUCCESS1
#endif
#ifndefFAILURE//标志位失败
#defineFAILURE0
#endif
#ifndefINF//标志位无穷
#defineINF0x3f3fffff
#endif
#ifndefMAXNUM
#defineMAXNUM20
#endif
typedefboolSTATUS;//定义函数状态数据类型
typedefcharVERTEXTYPE[MAXNUM][11];//定义顶点向量数据类型
typedefintADJMATRIX[MAXNUM][MAXNUM];//定义邻接矩阵数据类型
typedefstructGRAPH//定义图数据类型
{
VERTEXTYPEVexs;//图的顶点向量
ADJMATRIXArcs;//图的邻接矩阵
intVexNum;//图的当前顶点
intArcNum;//图的当前弧
}*PGRAPH;//定义图的指针数据类型
typedefstructCLOSEDGE//定义辅助数组数据类型
{
VERTEXTYPEVexs;//图的顶点向量
intLowcost[MAXNUM];//
}*PCLOSEDGE;//定义辅助数组指针数据类型
1.2。
3项目模块设计
创建景区景点分布图
一.邻接矩阵(AdjacencyMatrix)(二维数组表示法)
在图的邻接矩阵表示中,有一个记录各个顶点信息的顶点表,还有一个表示各个顶点之间关系的邻接矩阵。
设图A=(V,E)是一个有n个顶点的图,图的邻接矩阵是一个二维数组A。
edge[n][n],定义(满足如下条件的n阶矩阵):
无向图数组表示法特点:
1)无向图邻接矩阵是对称矩阵,同一条边表示了两次;
2)顶点v的度:
在无向图中等于二维数组对应行(或列)中1的个数;在有向图中,统计第i行1的个数可得顶点i的出度,统计第j列1的个数可得顶点j的入度。
3)判断两顶点v、u是否为邻接点:
只需判二维数组对应分量是否为1;
4)顶点不变,在图中增加、删除边:
只需对二维数组对应分量赋值1或清0;
5)设存储顶点的一维数组大小为n(图的顶点数n),G占用存储空间:
n+n2;G占用存储空间只与它的顶点数有关,与边数无关;适用于边稠密的图;
流程图:
程序:
//创建景区景点分布图
STATUSCreateGraph(PGRAPHpGraph)
{
printf(”\t\t\t_________________________________\n”);
printf(”\n\t\t\t$\t创建景区景点分布图\t$\n”);
printf(”\t\t\t_________________________________\n");
//初始化图的顶点数
printf(”\t\t\t初始化顶点数和弧度数。
.。
.。
.\n”);
printf(”\t\t\t请输入图的顶点数(〈=20):
”);
scanf(”%d",&pGraph—〉VexNum);
//检查
if(pGraph—〉VexNum〉20)
{
printf(”\t\t\t警告:
输入数据错误!
!
!
\n”);
printf("\t\t\t按任意键回主菜单!
!
!
”);
getch();
returnFAILURE;
}
//初始化图的弧数
printf("\t\t\t请输入图的弧度数(〈=20):
");
scanf(”%d”,&pGraph—>ArcNum);
//检查
if(pGraph—〉ArcNum>20)
{
printf(”\t\t\t警告:
输入数据错误!
!
!
\n");
printf(”\t\t\t按任意键回主菜单!
!
!
");
getch();
returnFAILURE;
}
//初始化图的顶点名称
printf(”\t\t\t——-——-——--—------——-———---———-———\n”);
printf(”\t\t\t初始化的顶点名称.。
。
。
。
.\n”);
for(inti=0;i〈pGraph-〉VexNum;i++)
{
printf(”\t\t\t请输入第%d个顶点名称:
”,i+1);
scanf(”%s",pGraph—〉Vexs[i]);
}
//初始化图的弧权值为最大值
for(i=0;iVexNum;i++)
for(intj=0;j〈pGraph—〉VexNum;j++)
pGraph->Arcs[i][j]=INF;
//输入弧的信息
printf(”\t\t\t——----————--—————--——-—————-——-—-\n");
printf("\t\t\t初始化的弧的信息。
。
.。
.。
\n");
printf(”\t\t\t请输入弧的信息(注:
从0开始):
\n”);
for(i=0;i{
intStav,Endv,Weight;
printf("\t\t\t请输入第%d条弧(格式:
ViVjWeight):
”,i+1);
scanf(”%d%d%d",&Stav,&Endv,&Weight);
pGraph—〉Arcs[Endv][Stav]=Weight;
pGraph—>Arcs[Stav][Endv]=Weight;
}
printf(”\t\t\t创建景区景点分布图成功!
!
!
\n");
printf("\t\t\t按任意键回主菜单!
!
!
”);
getch();
returnSUCCESS;
}
输出景区景点分布图
流程图:
程序:
//输出景区景点分布图
STATUSPrintGraph(constPGRAPHpGraph)
{
printf("\t\t\t_________________________________\n");
printf("\n\t\t\t$\t显示景区景点分布图\t$\n”);
printf("\t\t\t_________________________________\n\n”);
//
printf(”\t景区景点名称。
。
.。
..\n\t”);
for(inti=0;i〈pGraph—〉VexNum;i++)
printf("%s\t”,pGraph-〉Vexs[i]);
printf(”\n\n\t景区景点信息。
。
..。
。
\n”);
for(i=0;i{
printf(”\t___________________________________________________________\n\t”);
for(intj=0;j〈pGraph—>VexNum;j++)
if(pGraph->Arcs[i][j]==INF)
printf(”∞\t");
else
printf("%d\t”,pGraph—〉Arcs[i][j]);
printf(”\n");
}
printf("\t___________________________________________________________\n\t”);
printf(”按任意键回主菜单!
!
!
”);
getch();
returnSUCCESS;
}
输出景区导游线路图
图的遍历
从图中某一顶点出发访遍图中所有的顶点,且使每个顶点仅被访问一次,这一过程就叫做图的遍历(TraversingGraph)。
图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。
为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组visited[].
辅助数组visited[]的初始状态为0,在图的遍历过程中,一旦某一个顶点i被访问,就立即让visited[i]为1,防止它被多次访问。
两种图的遍历方法:
深度优先搜索
DFS(DepthFirstSearch)
广度优先搜索
BFS(BreadthFirstSearch)
广度优先搜索遍历图(BFS)
对连通图,从起始点V到其余各顶点必定存在路径。
其中,V-〉w1,V—〉w2,V—>w8的路径长度为1;
V—〉w7,V—>w3,V-〉w5的路径长度为2;
V->w6,V—〉w4的路径长度为3
从图中的某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到.
若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止.
流程图:
程序:
//输出景区导游线路图(注:
广度优先遍历)
STATUSTraverseGraph(constPGRAPHpGraph)
{
printf("\t\t\t_________________________________\n”);
printf("\n\t\t\t$\t输出景区导游线路图\t$\n”);
printf("\t\t\t_________________________________\n\n”);
//定义访问标志数组
bool*Visit=(bool*)malloc(pGraph—〉VexNum*sizeof(bool));
//初始化访问标志数组为false
for(inti=0;iVisit[i]=false;
//定义队列、并初始化队列
QUEUEQueue;
if(InitQueue(&Queue,pGraph—>VexNum)==FAILURE)
{
printf(”\t\t\t警告:
创建队列失败!
!
!
\n”);
printf("\t\t\t按任意键回主菜单!
!
!
”);
getch();
returnFAILURE;
}
//定义访问顶点变量,并初始值为0
intVertex=0;
do
{
if(!
Visit[Vertex])
{
printf(”\t\t\t%s景点.。
。
.。
。
\n”,pGraph->Vexs[Vertex]);
//标志访问过
Visit[Vertex]=true;
//遍历与Vertex相连的顶点并进队
for(i=0;i〈pGraph->VexNum;i++)
if(Visit[i]==false&&pGraph-〉Arcs[Vertex][i]!
=INF)
EnQueue(&Queue,i);
}
//出队
DeQueue(&Queue,&Vertex);
}while(QueueLen(&Queue));
//销毁队列
DestroyQueue(&Queue);
printf(”\t\t\t按任意键回主菜单!
!
!
");
getch();
returnSUCCESS;
}
有向图的拓扑排序
何谓“拓扑排序”?
对有向图进行如下操作:
假设G=(V,E)是一个具有n个顶点的有向图,V中顶点序列vl,v2,…,vn称做一个拓扑序列(TopologicalOrder),当且仅当该顶点序列满足下列条件:
若在有向图G中存在从顶点vi到vj的一条路径,则在顶点序列中顶点vi必须排在顶点vj之前。
通常,在AOV网中,将所有活动排列成一个拓扑序列的过程叫做拓扑排序(TopologicalSort)。
在AOV网中不应该出现有向环。
因为环的存在意味着某项活动将以自己为先决条件,显然无法形成拓扑序列。
判定网中是否存在环的方法:
对有向图构造其顶点的拓扑有序序列,若网中所有顶点都出现在它的拓扑有序序列中,则该AOV网中一定不存在环.
例如:
对于有向图
可求得拓扑有序序列:
ABCD或ACBD
例如,对学生选课工程图进行拓扑排序,得到的拓扑有序序列为
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)从图中删去该顶点,同时删去所有它发出的有向边;
重复以上步骤,直到全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;或图中还有未输出的顶点,但已跳出处理循环。
这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了.这时AOV网络中必定存在有向环。
在实现拓扑排序的算法中,采用邻接表作为有向图的存储结构,每个顶点设置一个单链表,每个单链表有一个表头结点,在表头结点中增加一个存放顶点入度的域count,这些表头结点构成一个数组。
为了避免重复检测入度为0的点,另设一栈存放所有入度为0的点。
对于有n个顶点和e条边的有向图而言,for循环中建立入度为0的顶点栈时间为O(n);若在拓扑排序过程中不出现有向环,则每个顶点出栈、入栈和入度减1的操作在while循环语句中均执行e次,因此拓扑排序总的时间花费为O(n+e)。
流程图:
程序:
//有向图的拓扑排序
STATUSTopologicalSort(constPGRAPHpGraph)
{
printf(”\t\t\t_________________________________\n”);
printf("\n\t\t\t$\t导游线路图有无回路\t$\n");
printf(”\t\t\t_________________________________\n\n”);
//定义入度数组,记录每个顶点的入度,初始化为0
intIndegree[MAXNUM]={0};
//定义桟、并初始化桟
STACKStack;
if(InitStack(&Stack,pGraph—>VexNum)==FAILURE)
{
printf(”\t\t\t警告:
创建桟失败!
!
!
\n”);
printf(”\t\t\t按任意键回主菜单!
!
!
");
getch();
returnFAILURE;
}
printf(”\t\t\t计算各顶点的入度.。
。
。
.\n”);
for(intj=0;jVexNum;j++)
{
//求各个顶点的入度
for(inti=0;i〈pGraph-〉VexNum;i++)
if(pGraph—〉Arcs[i][j]!
=INF)
Indegree[j]++;
//入度为0的顶点入栈
if(!
Indegree[j])
PushStack(&Stack,j);
}
printf(”\t\t\t进行拓扑排序。
。
。
.。
\n”);
//Count用来指示入度为0的顶点个数
intCount=0,k;
while(StackLen(&Stack))
{
//出桟、并访问
PopStack(&Stack,&k);
printf("%s\t",pGraph—〉Vexs[k]);
Count++;
//对出栈的顶点所指向的顶点减一,并且将入度为0的顶点入栈
for(inti=0;i〈pGraph->VexNum;i++)
if(pGraph—〉Arcs[k][i]!
=INF)
if(!
(—-Indegree[i]))
PushStack(&Stack,i);
}
//销毁桟
DestroyStack(&Stack);
//判断是否是拓扑排序
if(CountVexNum)
printf(”\t\t\t结果:
导游线路图有回路\n");
else
printf("\t\t\t结果:
导游线路图无回路\n");
printf(”\t\t\t按任意键回主菜单!
!
!
”);
getch();
returnSUCCESS;
}
求两个景点间的最短路径
最短路径定义
所谓最短路径问题是指:
如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径似的沿此路径上各边的权值总和(称为路径长度)达到最小.
迪杰斯特拉(Dijkstra)算法求单源最短路径
由Dijkstra提出的一种按路径长度递增序产生各顶点最短路径的算法.
(1)按路径长度递增序产生各顶点最短路径
若按长度递增的次序生成从源点s到其它顶点的最短路径,则当前正在生成的最短路径上除终点以外,其余顶点的最短路径均已生成(将源点的最短路径看作是已生成的源点到其自身的长度为0的路径)。
(2)具体做法
一开始第一组只包括顶点v1,第二组包括其他所有顶点,v1对应的距离值为0,第二组的顶点对应的距离值是这样确定的:
若图中有边若加进vm做中间顶点,使从v1到vj的最短路径比不加vm的路径为短,则要修改vj的距离值。
修改后再选距离最小的顶点加入到第一组中。
如此进行下去,直到图中所有顶点都包括在第一组中,或再也没有可加入到第一组中的顶点存在为止。
假设有向图G的n个顶点为1到n,并用邻接矩阵cost表示,若〈vi,vj>是图G中的边,则cost[i][j]的值等于边所带的权;若另外,设置三个数组S[n]、dist[n]、pre[n]。
S用以标记那些已经找到最短路径的顶点,若S[i—1]=1,则表示已经找到源点到顶点i的最短路径,若S[i—1]=0,则表示从源点到顶点i的最短路径尚未求得。
dist[i—1]用来记录源点到顶点i的最短路径。
pre[i—1]表示从源点到顶点i的最短路径上该点的前趋顶点,若从源点到该顶点无路径,则用0作为其前一个顶点序号。
流程图:
程序:
//求两个景点间的最短路径
STATUSMinShortPath(constPGRAPHpGraph)
{
printf(”\t\t\t_________________________________\n”);
printf(”\n\t\t\t$\t景点之间的最短路径\t$\n”);
printf("\t\t\t_________________________________\n\n");
//定义路径矩阵、距离矩阵
ADJMATRIXPathMatrix,DisMatrix;
//定义辅助变量
inti,j,k;
//初始化路径矩阵、距离矩阵
for(i=0;iVexNum;i++)
for(j=0;j〈pGraph—>VexNum;j++)
{
DisMatrix[i][j]=pGraph-〉Arcs[i][j];
PathMatrix[i][j]=—1;
}
//求PathMatrix矩阵
for(k=0;k〈pGraph->VexNum;k++)
for(i=0;i〈pGraph—〉VexNum;i++)
for(j=0;jif(DisMatrix[