烟台山旅游导航
【问题描述】
在旅游景区,经常会遇到游客打听从一个景点到另一个景点的最短路径和最短距离,这类游客不喜欢按照导游图的线路来游览,而是挑选自己感兴趣的景点游览。为于帮助这类游客信息查询,就需要计算出所有景点之间最短路径和最短距离。算法采用迪杰斯特拉算法或弗洛伊德算法均可。建立一个景区旅游信息管理系统,实现的主要功能包括制订旅游景点导游线路策略和制订景区道路铺设策略。
课程
任务中景点分布是一个无向带权连通图,图中边的权值是景点之间的距离。
(1)景区旅游信息管理系统中制订旅游景点导游线路策略,首先通过遍历景点,给出一个入口景点,建立一个导游线路图,导游线路图用有向图表示。遍历采用深度优先策略,这也比较符合游客心理。
(2)为了使导游线路图能够优化,可通过拓朴排序判断图中有无回路,若有回路,则打印输出回路中的景点,供人工优化。
(3)在导游线路图中,还为一些不愿按线路走的游客提供信息服务,比如从一个景点到另一个景点的最短路径和最短距离。在本线路图中将输出任意景点间的最短路径和最短距离。
(4)在景区建设中,道路建设是其中一个重要内容。道路建设首先要保证能连通所有景点,但又要花最小的代价,可以通过求最小生成树来解决这个问题。本任务中假设修建道路的代价只与它的里程相关。
【基本要求】
本任务应有如下功能模块:
创建景区景点分布图;
输出景区景点分布图(邻接矩阵)
输出导游线路图;
判断导游线路图有无回路;
求两个景点间的最短路径和最短距离;
输出道路修建规划图。
主程序用菜单选项供用户选择功能模块。
#include <cstdio> #include <cstdlib> #include <string> #include <cstring> #include <iostream> using namespace std ; const int MAX = 100 ; const int inf = 0x3f3f3f; // 景区旅游信息管理系统 typedef struct node { char PlaceName[MAX] ; // 景点的名字 int PlaceNumber ; // 景点编号 } Node; typedef struct route { int u ; int v ; int weight ; } Route; // 起点终点和距离 ; typedef struct matGraph { int map[MAX][MAX] ; int n , e ; } MatGraph; // 完整的图邻接矩阵类型 typedef struct NODE { Node infor ; // 信息 struct NODE *lchild ; struct NODE *rchild ; } BSTNode; typedef struct ANode { int adjvex ; // 编号 struct ANode *nextarc ; int weight ; } ArcNode ; // 边节点的类型 typedef struct Vnode { ArcNode *firstarc ; int count ; } VNode; // 邻接表的头结点类型 typedef struct { VNode adjlist[MAX] ; int n , e ; // 边数和顶点数 } AdjGraph; int vis[MAX] ; int count1 ; BSTNode *MapVex[MAX] ; // 顶点 void CreateMatGragh(MatGraph > ,int n , int pos, Route Gr[MAX][MAX]) { // 创建导游有向图 ; for(int i = 1 ; i<=n ; i++) { for(int j = 1 ; j <=n ; j++) { if(i == j ) { GT.map[i][j] = 0 ; } else { GT.map[i][j] = inf ; } } } for(int i = 1 ; i<= n; i++) { GT.map[Gr[pos][i].u][Gr[pos][i].v] = Gr[pos][i].weight ; } return ; } void Read(Node Place[] ,int n ,int e) { // 读取数据 FILE *fp ; fp = fopen("map.txt","r"); if(fp == NULL) { return ; } for(int i = 1 ; i<=n ; i++) { fscanf(fp,"%s %d",Place[i].PlaceName,&Place[i].PlaceNumber); } return ; } void MatToList(MatGraph g , AdjGraph *&G) { //将邻接矩阵转换成邻接表 ArcNode *p ; // 边节点 G = (AdjGraph *)malloc(sizeof(AdjGraph)) ; for(int i = 1 ; i<=g.n ; i++) { G->adjlist[i].firstarc = NULL ; } for(int i = 1 ; i<= g.n ; i++) { for(int j = g.n ; j >=1 ; j--) { if(g.map[i][j]!= 0 && g.map[i][j] !=inf ) { p = (ArcNode *)malloc(sizeof(ArcNode)) ; p->adjvex = j ; p->weight = g.map[i][j] ; p->nextarc = G->adjlist[i].firstarc ; G->adjlist[i].firstarc = p ; } } } G->n = g.n ; G->e = g.e ; return ; } int DispAdj(AdjGraph *G ) { // 输出邻接表 ArcNode *p ; int count = 0 ; for(int i = 1 ; i <=G->n ; i++ ) { p = G->adjlist[i].firstarc ; printf("%3d: " ,i ) ; while(p!=NULL ) { printf("%3d[%d]-> ", p->adjvex , p->weight ) ; p = p->nextarc ; count++ ; } printf(" ^ \n") ; } return count; } BSTNode *SearchBST(BSTNode *bt , int k ) { // 在二叉搜素树中查找 编号为k 的节点 // return 节点的地址 if(bt == NULL || bt->infor.PlaceNumber == k ) { return bt ; } if(k < bt->infor.PlaceNumber) { return SearchBST(bt->lchild , k) ; } else { return SearchBST(bt->rchild , k ) ; } } void DFS(AdjGraph *G , int v , Node Place[] ,BSTNode *bt ) { // 深度优先搜素 ArcNode *p ; BSTNode *Root ; vis[v] = 1 ; //printf("%d ",v); Root = SearchBST(bt,v) ;// 在二叉排序树中找到 if(Root!=NULL) { cout<<Root->infor.PlaceName <<"-> " ; MapVex[++count1]= Root ;// 将DFS创建的节点依次加入到导游图中 // 创建导游图, } p = G->adjlist[v].firstarc ; while(p!=NULL) { if(vis[p->adjvex] == 0 ) { vis[p->adjvex] = 1 ; DFS(G,p->adjvex,Place,bt) ; } p = p->nextarc ; } } void Display(Node Place[] ,int n) { // 显示所有景点名字 cout<<"景点名字\t 编号\n" ; for(int i = 1 ; i<=n ; i++) { printf("%8s\t%8d\n",Place[i].PlaceName,Place[i].PlaceNumber); } } void CreateMat(MatGraph &Map , int n , int e) { // 创建邻接矩阵 FILE *fp ; fp = fopen("edge.txt","r"); for(int i = 1 ; i<=n ; i++) { for(int j = 1 ; j<=n ; j++) { Map.map[i][j] = inf ; if(i == j ) Map.map[i][j] = 0 ; } } Map.n = n ; Map.e = e ; for(int i = 1 ; i<=e ; i++) { int u, v, w; fscanf(fp, "%d %d %d", &u, &v, &w); Map.map[u][v] = w ;// 无向图 Map.map[v][u] = w ; } return ; } bool InsertBST(BSTNode *&bt , Node k ) { // 二叉排序树插入节点 if(bt==NULL) { bt = (BSTNode*)malloc(sizeof(BSTNode)) ; bt->infor.PlaceNumber = k.PlaceNumber ; strcpy(bt->infor.PlaceName,k.PlaceName) ; bt->lchild = NULL ; bt->rchild = NULL ; return true ; } else if (k.PlaceNumber == bt->infor.PlaceNumber) { return false ; } else if (k.PlaceNumber < bt->infor.PlaceNumber ) { return InsertBST(bt->lchild , k) ; } else if (k.PlaceNumber > bt->infor.PlaceNumber ) { return InsertBST(bt->rchild , k) ; } } BSTNode *CreatBST(Node Place[] , int n) { // 创建二叉排序树 ; BSTNode *bt = NULL; for(int i = 1; i <=n ; i++) { InsertBST(bt,Place[i]) ; } return bt ; } void Dijkstra(int start, int end, MatGraph Map,BSTNode *bt) { // 最短路Dijkstra 实现 int n , e ; int Path[MAX] ; int dis[MAX] ; n = Map.n ; e = Map.e ; memset(vis,0,sizeof(vis)) ; memset(Path,0,sizeof(Path)) ; for(int i = 1; i <= n; i++) { dis[i] = Map.map[start][i] ; if(Map.map[start][i] < inf) { Path[i] = start ; } else { Path[i] = 0 ; } } vis[start] = 1 ; Path[start] = 0 ; for(int i = 1 ; i<n ; i++) { int minn = inf ; int u = -1 ; for(int j = 1 ; j<=n ; j++) { if(!vis[j] && dis[j]<minn) { minn = dis[j] ; u = j ; } } if(u != -1) { vis[u] = 1 ; for(int v = 1 ; v <=n; v++) { if(Map.map[u][v] < inf && vis[v] == 0) { if(dis[v] > dis[u] + Map.map[u][v]) { dis[v] = dis[u] + Map.map[u][v] ; Path[v] = u ; } } } } } BSTNode *pfind1 ,*pfind2,*pfind3; int pre ; for(int i=1; i<=n; i++) //输出结果和最短路径 { pfind1 = SearchBST(bt,start) ; pfind2 = SearchBST(bt,i) ; if(pfind1 && pfind2) { if(end == pfind2->infor.PlaceNumber) { printf("%s 到 %s的最短距离为 ",pfind1->infor.PlaceName,pfind2->infor.PlaceName); printf("%d m\n",dis[i]); //打印结果 pre = Path[i]; printf("路径:%s", pfind2->infor.PlaceName); } while(pre!=0) //继续找前趋顶点 { pfind3 = SearchBST(bt,pre) ; if(pfind1) { printf("<——%s",pfind3->infor.PlaceName); pre=Path[pre]; } else return ; } } else { cout<<"输入错误 "<<endl; return ; } } return ; } void Prim(MatGraph Map ,int start ,BSTNode *bt) { // 最小生成树 int lowcost[MAX] ; int MIN ; int closet[MAX] , i , j , k ; cout<<"道路修建规划 : "<<endl; for(i = 1 ; i <= Map.n ; i++) { lowcost[i] = Map.map[start][i] ; closet[i] = start ; } for( i = 1 ; i<Map.n ; i++) { MIN = inf ; for(j = 1 ; j<=Map.n ; j++) { if(lowcost[j]!=0 && lowcost[j] <MIN) { MIN = lowcost[j] ; k = j ; } } BSTNode *s = SearchBST(bt,closet[k]) ; BSTNode *sz = SearchBST(bt,k) ; if(s != NULL && sz != NULL) { cout << s->infor.PlaceName << " - " << sz->infor.PlaceName <<endl; } lowcost[k] = 0 ; for(int j = 1; j <= Map.n; j++) { if(lowcost[j] != 0 && Map.map[k][j] < lowcost[j]) { lowcost[j] = Map.map[k][j] ; closet[j] = k ; } } } } void InOrder(BSTNode *bt ) { // 中序 if(bt != NULL) { InOrder(bt->lchild) ; cout << bt->infor.PlaceNumber << " " << bt->infor.PlaceName <<endl ; InOrder(bt->rchild) ; } return ; } void PageInfor() { system("color A"); cout<<"\t\t\t *********************************************"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t * 烟台山景区 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 1 创建景区景点分布图 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 2 输出景区景点分布图 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 3 输出导游路线 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 4 输出最佳导游路线 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 5 输出最短路径 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 6 输出道路修建规划图 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *\t"<<" "<<" 7 退出系统 *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t * *"<<endl; cout<<"\t\t\t *********************************************"<<endl; cout << "功能选择 >> : "; } int main() { int n = 13 ; int e = 14 ; Route Gr[MAX][MAX] ; MatGraph Map ; int TourMap[MAX][MAX]; AdjGraph *G ;// 邻接表 Node Place[MAX] ; // 所有的景点信息 BSTNode *bt ; // 二叉排序树根节点 cout<<endl<<endl; int num ; Read(Place,n,e) ; // 读入数据 PageInfor() ; // 显示页面信息 while(cin >> num && num!=7) { if(num == 1 ) { CreateMat(Map,n,e) ; cout<<"地图创建成功 "<<endl; } else if(num == 2 ) { cout<<"--所有景点信息-- \n"; cout<<"景点名字\t 编号\n" ; for(int i = 1 ; i <=n ; i++) { cout<<Place[i].PlaceName<< " : "<<Place[i].PlaceNumber <<endl; } cout<<"景区地图 "<<endl ; for(int i = 1 ; i<= n ; i++) { cout<<" "<<i ; } cout<<endl; int k = 1 ; for(int i = 1 ; i <=n ; i++) { cout<<k++ <<" "; for(int j = 1 ; j<=n ; j++) { if(Map.map[i][j] == inf ) { cout<<"∞"<<" " ; } else { printf("%d ",Map.map[i][j]); } } cout<<endl ; } cout<<endl ; } else if(num == 3 ) { // 输出所有的旅游路线 ; bt = CreatBST(Place,n); // 创建二叉排序树 cout<<"所有景点如下 : "<<endl ; InOrder(bt) ;// 中序遍历二叉树 cout<<endl; MatToList(Map ,G) ; // 转化成邻接表 printf("所有的导游路线 : \n" ) ; cout<<endl ; for(int i = 1 ; i<=n; i++) { cout<< "方案 "<<i<<" : \n " ; memset(vis,0,sizeof(vis)) ; memset(MapVex,0,sizeof(MapVex) ) ; //对每个顶点进行dfs DFS(G,i,Place,bt) ; count1 = 0; cout<<endl<<endl ; for(int j = 1 ; j<=n ; j++) { int u = MapVex[j]->infor.PlaceNumber; // dfs后导游路线上的景点编号 TourMap[i][j] = u ; } } } else if (num == 4 ) { cout << endl; for(int i = 1 ; i <=n ; i++) { for(int j = 1 ; j < n ; j++) { Gr[i][j].u = TourMap[i][j] ; // 起点 Gr[i][j].v = TourMap[i][j+1] ; // 终点 Gr[i][j].weight = Map.map[TourMap[i][j]][TourMap[i][j+1]] ; } } MatGraph GT[20] ; // 导游路线图 for(int i = 1 ; i<=n ; i++) CreateMatGragh(GT[i],n,i,Gr) ; // GT[1] 就是第一个导游路线(有向图) int number ; int edgenum[MAX] ; for(int k = 1 ; k <= n ; k++) { for(int i = 1 ; i <= n ; i++) { for(int j = 1 ; j <= n ; j++) { if(GT[k].map[i][j]!=inf && GT[k].map[i][j]!=0) { edgenum[k]++ ; } } } } for(int i = 1 ; i<=n ; i ++) { if(edgenum[i] == n-1) { number = i ; // 找到最佳路线图 ; break ; } } cout<<" 最佳导游路线 "<<endl ; for(int i = 1 ; i <=n ; i++) { // 二叉搜索树,依次输出景点 BSTNode *r = SearchBST(bt,TourMap[number][i]); // 查找最佳路线图 cout << r->infor.PlaceName ; if(i != n) cout << " -> "; } cout<<endl<< endl ; } else if (num == 5 ) { bt = CreatBST(Place,n); BSTNode *pfind1 ,*pfind2 ; cout<<endl; Display(Place,n) ; cout<<endl; int start, end; printf("输入起点景点编号 \n"); cin >> start ; printf("输入终点景点编号 \n") ; cin >>end ; int Find_Start_Num = start; int Find_End_Num = end; pfind1 = SearchBST(bt,Find_Start_Num) ;//顶点 pfind2 = SearchBST(bt,Find_End_Num) ; // 终点 if(!pfind1 && !pfind2) return 0; else cout<<pfind1->infor.PlaceName << " - > " <<pfind2->infor.PlaceName <<endl; if(Find_Start_Num != -1 && Find_End_Num != -1) { Dijkstra(Find_Start_Num, Find_End_Num, Map, bt) ; } else { cout << "输入错误 \n"; return 0; } cout << endl << endl; } else if (num == 6 ) { bt = CreatBST(Place, n); Prim(Map, 1, bt); } else if (num == 7 ) { // 终止程序 cout<<"退出系统成功 "<<endl ; return 0; } PageInfor() ; } return 0 ; }