資料結構 -- 景區旅遊資訊管理系統
景區旅遊資訊管理系統
【問題描述】
在旅遊景區,經常會遇到遊客打聽從一個景點到另一個景點的最短路徑和最短距離,這類遊客不喜歡按照導遊圖的線路來遊覽,而是挑選自己感興趣的景點遊覽。為於幫助這類遊客資訊查詢,就需要計算出所有景點之間最短路徑和最短距離。演算法採用迪傑斯特拉演算法或弗洛伊德演算法均可。建立一個景區旅遊資訊管理系統,實現的主要功能包括制訂旅遊景點導遊線路策略和制訂景區道路鋪設策略。
課程
任務中景點分佈是一個無向帶權連通圖,圖中邊的權值是景點之間的距離。
(1)景區旅遊資訊管理系統中制訂旅遊景點導遊線路策略,首先通過遍歷景點,給出一個入口景點,建立一個導遊線路圖,導遊線路圖用有向圖表示。遍歷採用深度優先策略,這也比較符合遊客心理。
(2)為了使導遊線路圖能夠優化,可通過拓樸排序判斷圖中有無迴路,若有迴路,則列印輸出迴路中的景點,供人工優化。
(3)在導遊線路圖中,還為一些不願按線路走的遊客提供資訊服務,比如從一個景點到另一個景點的最短路徑和最短距離。在本線路圖中將輸出任意景點間的最短路徑和最短距離。
(4)在景區建設中,道路建設是其中一個重要內容。道路建設首先要保證能連通所有景點,但又要花最小的代價,可以通過求最小生成樹來解決這個問題。本任務中假設修建道路的代價只與它的里程相關。
【基本要求】
本任務應有如下功能模組:
建立景區景點分佈圖;
輸出景區景點分佈圖(鄰接矩陣)
輸出導遊線路圖;
判斷導遊線路圖有無迴路;
求兩個景點間的最短路徑和最短距離;
輸出道路修建規劃圖。
主程式用選單選項供使用者選擇功能模組。
因為時間很倉促,做的不是很好,判斷導遊線路圖我沒用拓撲排序(寫了沒用) .
然後我的邊和景點資訊存在工程下目錄edge 和 map 兩個檔案中.
程式碼 :
#include <cstdio> #include <cstdlib> #include <string> #include <cstring> #include <algorithm> #define path "map.txt" #include <windows.h> #include <vector> #include <iostream> using namespace std ; const int MAX = 105 ; const int inf = 0x3f3f3f; // 景區旅遊資訊管理系統 typedef struct node{ char PlaceName[MAX] ; // 景點的名字 int number ; // 景點編號 char PlaceNum[MAX] ; // 編號 ; }Node; typedef struct Tornode{ int u ; int v ; int weight ; }TorNode; // 起點終點和距離 ; typedef struct matGraph{ int map[MAX][MAX] ; int n , e ; }MatGraph;// 完整的圖鄰接矩陣型別 typedef struct NODE{ int key ;// 關鍵字項 Node infor ; // 資訊 struct NODE *lchild ; struct NODE *rchild ; }BSTNode; typedef struct ANode{ int adjvex ; // 編號 struct ANode *nextarc ; int weight ; }ArcNode ; // 邊節點的型別 typedef struct Vnode{ ArcNode *fitstarc ; int count ; }VNode; // 鄰接表的頭結點型別 typedef struct { VNode adjlist[MAX] ; int n , e ; // 邊數和頂點數 }AdjGraph; int vis[MAX] ; int dis[MAX] ; int count1 ; BSTNode *MapVex[MAX] ; // 頂點 void CreatMatGragh(MatGraph > ,int n ,int e , int pot, TorNode 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 ; } GT.map[i][j] = inf ; } } for(int i = 1 ; i<=e ; i++) { GT.map[Gr[pot][i].u][Gr[pot][i].v] = Gr[pot][i].weight ; } return ; } int cmp(const Node &a , const Node &b) { return a.number <b.number ; } int digit(int x ) { // 計算位數 int t = x ; int k = 0 ; while(t) { k++; t/=10 ; } return k ; } char *transtr(int n) { //轉換成字串 //char t[MAX] ; char t[MAX] ; int i = 0 ,x = n ; while(x) { t[digit(n) - i-1] = (x%10) + '0' ; x/=10 ; i++; } return t ; } void Read(Node Place[] ,int n ,int e) { // 讀取資料 FILE *fp ; fp = fopen(path,"r"); if(fp == NULL) { perror("fopen\n") ; exit(-1) ; } for(int i = 1 ; i<=n ; i++) { fscanf(fp,"%s %d",Place[i].PlaceName,&Place[i].number); int d = digit(Place[i].number) ; char Tmp[MAX] = "000"; if(d==1) { strcpy(Place[i].PlaceNum,transtr(Place[i].number)) ; strcat(Tmp,Place[i].PlaceNum) ; strcpy(Place[i].PlaceNum,Tmp) ; } else if(d==2) { char Tmp[MAX] = "00"; strcpy(Place[i].PlaceNum,transtr(Place[i].number)) ; strcat(Tmp,Place[i].PlaceNum) ; strcpy(Place[i].PlaceNum,Tmp) ; } else if(d==3) { char Tmp[MAX] = "0"; strcpy(Place[i].PlaceNum,transtr(Place[i].number)) ; strcat(Tmp,Place[i].PlaceNum) ; } } 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].fitstarc = 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].fitstarc ; G->adjlist[i].fitstarc = 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].fitstarc ; 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.number == k ) { return bt ; } if(k < bt->infor.number) { return SearchBST(bt->lchild , k) ; } else { return SearchBST(bt->rchild , k ) ; } } void TopSort(AdjGraph *G) { // 拓撲排序 ; int St[MAX] , top = -1 ; ArcNode * p ; for(int i = 1 ; i<=G->n ; i++) { G->adjlist[i].count = 0 ; // 初始化 } for(int i = 1 ; i<=G->n ; i++) { p = G->adjlist[i].fitstarc ; while(p!=NULL) { G->adjlist[p->adjvex].count++ ; p = p->nextarc ; } } for(int i = 1 ; i <=G->n ; i++) { if(G->adjlist[i].count == 0 ) { top++ ; St[top] = i ; } } int i , j ; while(top>-1) { i = St[top] ; top -- ; cout<<i<<" " ; p = G->adjlist[i].fitstarc ; while(p!=NULL) { j = p->adjvex ; G->adjlist[j].count -- ; if(G->adjlist[j].count ==0 ) { top++ ; St[top] = j ; } p = p->nextarc ; // 下一個鄰接點 ; } } } 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)// 小心駛得萬年船,不加會異常 { // if(vis[p->adjvex] = 0 ) cout<<Root->infor.PlaceName <<"-> " ; MapVex[++count1]= Root ;// 將DFS建立的節點依次加入到導遊圖中 // 建立導遊圖, } p = G->adjlist[v].fitstarc ; while(p!=NULL) { if(vis[p->adjvex] == 0 ) { vis[p->adjvex] = 1 ; // DFS(G,p->adjvex,Place,bt) ; //vis[p->adjvex] = 0 ; // } p = p->nextarc ; } } void Display(Node Place[] ,int n) { // 顯示所有景點名字 cout<<"景點名字\t 編號\n" ; for(int i = 1 ; i<=n ;i++) { printf("%8s\t%8s\n",Place[i].PlaceName,Place[i].PlaceNum); // cout<<Place[i].PlaceName<< "\t"<<Place[i].PlaceNum<<endl; Sleep(100); } } void CreadMat(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.number = k.number ; strcpy(bt->infor.PlaceName,k.PlaceName) ; strcpy(bt->infor.PlaceNum,k.PlaceNum); bt->lchild = NULL ; bt->rchild = NULL ; return true ; } else if (k.number == bt->infor.number) { return false ; } else if (k.number < bt->infor.number ) { return InsertBST(bt->lchild , k) ; } else if (k.number > bt->infor.number ) { 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 cur,MatGraph Map,BSTNode *bt ,int End) { // 最短路Dijkstra 實現 int n , e ; int Path[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[cur][i] ; if(Map.map[cur][i] < inf) { Path[i] = cur ; } else { Path[i] = 0 ; } } vis[cur] = 1 ; Path[cur] = 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,cur) ; pfind2 = SearchBST(bt,i) ; if(pfind1 && pfind2) { if(End == pfind2->infor.number) { printf("%s 到 %s的最短距離為 ",pfind1->infor.PlaceName,pfind2->infor.PlaceName); printf("%d m\n",dis[i]); //列印結果 pre = Path[i]; printf("路徑:%d",i); } while(pre!=0) //繼續找前趨頂點 { pfind3 = SearchBST(bt,pre) ; if(pfind1) { printf("<——%s",pfind3->infor.PlaceName); pre=Path[pre]; } else exit(0) ; } } else { cout<<"輸入錯誤 "<<endl; exit(0) ; } } return ; } void Prim(MatGraph Map ,int cur ,BSTNode *bt) { // 最小生成樹 int lowcost[MAX] ; int MIN ; int closet[MAX] , i , j , k ; cout<<"道路修建規劃 : "<<endl; for( i = 1 ; i<=Map.n ; i++) { //cout<<Map.map[cur][i]<<" " ; lowcost[i] = Map.map[cur][i] ; closet[i] = cur ; } 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 ; } //printf("(%d ,%d) : %d \n ",closet[k],k ,MIN) ; 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 ; } } } } int Find(char *a, Node M[],int n ) { //查詢 int i ; bool find = false ; for( i = 1 ; i <=n ; i++) { if(strcmp(a,M[i].PlaceName)==0) { find = true ; break ; } } return find?M[i].number:-1; } void InOrder(BSTNode *bt ) { // 中序 if(bt!=NULL) { InOrder(bt->lchild) ; cout<<bt->infor.number <<" " <<bt->infor.PlaceName <<" "<<bt->infor.PlaceNum <<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 *\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<<"功能選擇 >> : "; } void DisplayMenu(int n ,int e ) { TorNode Gr[MAX][MAX] ; MatGraph Map ,TMP ,TorMap; int TourMap[MAX][MAX]; AdjGraph *G ;// 鄰接表 Node Place[MAX] ; // 所有的景點資訊 char start[MAX] ,end[MAX] ; // 起點和終點 BSTNode *bt ; // 二叉排序樹根節點 cout<<endl<<endl; int num ; Read(Place,n,e) ; // 讀入資料 PageInfor() ; // 顯示頁面資訊 while(cin >> num && num!=7) { if(num == 1 ) { CreadMat(Map,n,e) ; cout<<"地圖建立成功 "<<endl; } else if(num == 2 ) { // 顯示景點圖 //Display(Place,n) ; cout<<"☆所有景點資訊☆ \n"; cout<<"景點名字\t 編號\n" ; for(int i = 1 ; i <=n ; i++) { cout<<Place[i].PlaceName<< " : "<<Place[i].number <<" : "<<Place[i].PlaceNum<<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) ; // 轉化成鄰接表 //DispAdj(G) ; //cout<<"dfs "<<endl ; int v = 2 ; printf("所有的導遊路線 : \n" ) ; cout<<endl ; int num ; for(int i = 1 ; i<=n; i++) { cout<< "方案 "<<i<<" : \n " ; memset(vis,0,sizeof(vis)) ; memset(MapVex,0,sizeof(MapVex) ) ; DFS(G,i,Place,bt) ; count1 = 0 ; cout<<endl<<endl ; for(int j = 1 ; j<=n ; j++) { int u = MapVex[j]->infor.number ; TourMap[i][j] = u ; } } } else if (num == 4 ) { TorMap.e = e ; TorMap.n = n ; cout<<endl; int StrageWeight[MAX][MAX] ; 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]] ; //StrageWeight[i][j] = Map.map[TourMap[i][j]][TourMap[i][j+1]] ; } } // 見圖 MatGraph GT[20] ; // 導遊路線圖 for(int i = 1 ; i<=n ;i++) CreatMatGragh(GT[i],n,e,i,Gr) ; int number ; int edgenum[MAX ] ; int ed = 0 ; 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) { 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 ; } else if (num == 5 ) { bt = CreatBST(Place,n); BSTNode *pfind1 ,*pfind2 ; cout<<endl; Display(Place,n) ; cout<<endl; printf("輸入起點景點 \n"); cin >> start ; printf("輸入終點景點 \n") ; cin >>end ; int Find_Start_Num = Find(start,Place,Map.n) ; int Find_End_Num = Find(end,Place,Map.n) ; pfind1 = SearchBST(bt,Find_Start_Num) ;//頂點 pfind2 = SearchBST(bt,Find_End_Num) ; // 終點 if(!pfind1 && !pfind2) exit(ERROR) ; else cout<<pfind1->infor.PlaceName << " - > " <<pfind2->infor.PlaceName <<endl; if(Find_Start_Num != -1 && Find_End_Num != -1) { Dijkstra(Find_Start_Num,Map,bt,Find_End_Num) ; } else { printf("輸入錯誤 \n"); exit(-1) ; } } else if (num == 6 ) { bt = CreatBST(Place,n); Prim(Map ,1,bt ); } else if (num == 7 ) { // 終止程式 cout<<"退出系統成功 "<<endl ; exit(0) ; } system("pause") ; PageInfor() ; } return ; } int main() { int n = 13 ; int e = 14 ; DisplayMenu(n,e ) ; return 0 ; }