圖與景區管理系統


圖與景區管理系統

功能簡介

序號 功能 實現原理
1 創建景區景點圖 文件讀寫、結構體
2 查詢景點信息 邊的關系
3 旅游景點導航 鏈表、深度優先搜索
4 搜索最短路徑 Dijkstra算法、最短路徑
5 鋪設電路規划 Prim算法、最小生成樹
0 退出 exit(0)

源代碼(Visual Studio 2017下)

數據結構頭文件

Graph.h

#ifndef GRAPH_H
#define GRAPH_H

struct Vex
{
	int num;//景點編號
	char name[20];//景點名字
	char desc[1024];//景點介紹
};
struct Edge
{
	int vex1;//邊的第一個頂點
	int vex2;//邊的第二個頂點
	int weight;//權值
};
struct Graph
{
	int m_aAdjMatrix[20][20];//鄰接矩陣
	Vex m_aVexs[20];//頂點信息組數
	int m_nVexNum;//當前圖的頂點個數
};
typedef struct Path
{
	int vexs[20];//保存一條路徑
	Path *next;//下一條路徑
}*PathList;//鏈表PathList用來保存所有路徑

void Init(void);
bool InsertVex(Vex sVex);
bool InsertEdge(Edge sEdge);
Vex GetVex(int nVex);
int FindEdge(int nVex, Edge aEdge[]);
int GetVexnum(void);
void DFS(int nVex, bool isVisited[], int &nIndex, PathList &pList);
void DFSTraverse(int nVex,PathList &pList);
bool TraverseOrNot(int now[], int i);
int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[]);
int FindMinTree(Edge aPath[]);
#endif GRAPH_H

數據結構源文件Graph.cpp


#include"Graph.h"
#include<iostream>
using namespace std;
Graph graph;
int EdgeNum;
Edge aEdge[100];
int allPath[20][20] = {0};
int PathNum=0;
//bool isVisited[20];
bool TraverseOrNot(int now[], int i)
{
	for (int p = 0; p < PathNum; p++)
	{
		for (int q = 0; q < i; q++)
		{
			if (allPath[p][q] != now[q])
			{
				break;
			}
			if ((allPath[p][q] == now[q] && q == i))
				return true;//曾被訪問
		}
	}
	return false;
}


void Init(void)
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 20; j++)
		{
			if (i == j)
				graph.m_aAdjMatrix[i][j] = 0;
			else
				graph.m_aAdjMatrix[i][j] = 0xffff;
		}
	}
	graph.m_nVexNum = 0;
}

bool InsertVex(Vex sVex)
{
	if (graph.m_nVexNum >= 20)
	{//頂點已滿
		return false;
	}
	graph.m_aVexs[graph.m_nVexNum++] = sVex;
	return true;
}

bool InsertEdge(Edge sEdge)
{
	if (sEdge.vex1 == sEdge.vex2)
		return false;
	graph.m_aAdjMatrix[sEdge.vex1][sEdge.vex2] = sEdge.weight;
	graph.m_aAdjMatrix[sEdge.vex2][sEdge.vex1] = sEdge.weight;
	return true;
}

Vex GetVex(int nVex)
{
	return graph.m_aVexs[nVex];
}
/*
int FindEdge(int nVex, Edge aEdge[])
{
	for (int i = 0; i < EdgeNum; i++)
	{
		if (aEdge[i].vex1 == nVex)
		{
			cout << graph.m_aVexs[aEdge[i].vex1].name << "->" << graph.m_aVexs[aEdge[i].vex2].name << " " << aEdge[i].weight << endl;
		}
		if(aEdge[i].vex2 == nVex)
			cout << graph.m_aVexs[aEdge[i].vex2].name << "->" << graph.m_aVexs[aEdge[i].vex1].name << " " << aEdge[i].weight << endl;
	}
	return true;
}
*/

int FindEdge(int nVex, Edge aEdge[])
{
	int k = 0;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		if (graph.m_aAdjMatrix[i][nVex] > 0 && graph.m_aAdjMatrix[i][nVex] < 0xffff)
		{
			aEdge[k].vex1 = nVex;
			aEdge[k].vex2 = i;
			aEdge[k].weight = graph.m_aAdjMatrix[i][nVex];
			k++;
		}
	}
	return k;
}

int GetVexnum(void)
{
	return graph.m_nVexNum;
}
/*
//輸出一行的深度優先搜索
void DFS(int nVex, bool isVisited[], int &nIndex, PathList &pList)
{//nIndex記錄遍歷的深度
	if (nIndex == graph.m_nVexNum - 1)
		pList->next = NULL;
	isVisited[nVex] = true;
	pList->vexs[nIndex++] = nVex;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		if (graph.m_aAdjMatrix[nVex][i] > 0 && graph.m_aAdjMatrix[nVex][i] < 0xffff && !isVisited[i]&&pList->next)
		{
			DFS(i, isVisited, nIndex, pList);//遞歸調用DFS
			isVisited[i] = false;
			nIndex--;
		}
	}
}
*/
void DFS(int nVex, bool isVisited[], int &nIndex, PathList &pList)
{//nIndex記錄遍歷的深度


	//if (nIndex == graph.m_nVexNum -1 && TraverseOrNot(pList->vexs, graph.m_nVexNum))
	//{
	//	nIndex--;
	//}

	isVisited[nVex] = true;
	pList->vexs[nIndex++] = nVex;
	//判斷是否所有的頂點都已被訪問過
	int nVexNum = 0;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		if (isVisited[i])
			nVexNum++;
	}
	if (nIndex == graph.m_nVexNum )
	{
		pList ->next= (PathList)malloc(sizeof(Path));
		for (int i = 0; i < graph.m_nVexNum; i++)
		{
			pList->next->vexs[i] = pList->vexs[i];
		}
		pList = pList->next;
		pList->next = NULL;
	}

	else 
	{
		for (int i = 0; i < graph.m_nVexNum; i++)
		{
			if (graph.m_aAdjMatrix[nVex][i] > 0 && graph.m_aAdjMatrix[nVex][i] < 0xffff && !isVisited[i])
			{
				DFS(i, isVisited, nIndex, pList);//遞歸調用DFS
				isVisited[i] = false;
				nIndex--;
			}
		}
	}

}

void DFSTraverse(int nVex, PathList &pList)
{
	int nIndex = 0;
	bool isVisited[20] = { false };
	DFS(nVex, isVisited, nIndex, pList);
}

int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[])
{
	int nShortPath[20][20];//保存最短路徑
	int nShortDistance[20];//保存最短距離
	bool isVisited[20];//判斷某頂點是否已加入到最短路徑
	int v;

	//初始化
	for (v = 0; v < graph.m_nVexNum; v++)
	{
		isVisited[v] = false;
		if (graph.m_aAdjMatrix[nVexStart][v])
		{
			//初始化該頂點到其他頂點的最短距離,默認為兩頂點間的距離
			nShortDistance[v] = graph.m_aAdjMatrix[nVexStart][v];
		}
		else
		{
			//如果兩頂點v和nVexStart不相連,則最短距離為最大值
			nShortDistance[v] = 0xffff;
		}
		nShortPath[v][0] = nVexStart;//起始點為nVexStart
		for (int w = 1; w < graph.m_nVexNum; w++)
		{
			nShortPath[v][w] = -1;//初始化最短路徑
		}
	}
	//初始化,nVexStart頂點加入到集合中
	isVisited[nVexStart] = true;
	int min;
	for (int i = 1; i < graph.m_nVexNum; i++)
	{
		min = 0xffff;
		bool bAdd = false;//判斷是否還有頂點可以加入集合
		for (int w = 0; w < graph.m_nVexNum; w++)
		{
			if (!isVisited[w])
			{
				if (nShortDistance[w] < min)
				{
					v = w;//頂點離nVexStart最近
					min = nShortDistance[w];//最短距離為min
					bAdd = true;
				}
			}
		}
		//如果沒有頂點可加入集合,則跳出循環
		if (!bAdd)
		{
			break;
		}
		isVisited[v] = true;//將w頂點加入到集合
		nShortPath[v][i] = v;
		for (int w = 0; w < graph.m_nVexNum; w++)
		{
			if (!isVisited[w] && (min + graph.m_aAdjMatrix[v][w] < nShortDistance[w]) /*&& (min + graph.m_aAdjMatrix[v][w]) < 0xffff*/)
			{
				//更新當前最短路徑及距離
				nShortDistance[w] = min + graph.m_aAdjMatrix[v][w];
				for (int i = 0; i < graph.m_nVexNum; i++)
				{
					//如果通過w到達頂點i的距離比較短,則將w的最短路徑復制給i
					nShortPath[w][i] = nShortPath[v][i];
				}
			}
		}
		for (int p = 0; p < graph.m_nVexNum; p++)
		{
			for (int j = 0; j < graph.m_nVexNum; j++)
			{
				cout<<nShortPath[p][j]<<" ";
			}
			cout << endl;
		}
		cout << endl;
	}
	int nNum=0;
	int finalpath[20];
	int onlypath[20] = { 0 };
	int q = 0;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		finalpath[i] = nShortPath[nVexEnd][i];
	}
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		if (finalpath[i] != -1)
		{
			nNum++;
			onlypath[q++] = finalpath[i];
		}
	}
	for (int i = 0; i < nNum-1; i++)
	{
		aPath[i].vex1 = onlypath[i];
		aPath[i].vex2 = onlypath[i + 1];
//		aPath[i].weight = nShortDistance[onlypath[i+1]];
		aPath[i].weight = graph.m_aAdjMatrix[aPath[i].vex1][aPath[i].vex2];
	//	if (i > 0)
	//	{
	//		aPath[i].weight = nShortDistance[onlypath[i + 1]] - nShortDistance[onlypath[i]];
			
	//	}
	}
	return nNum;
}
/*
int FindMinTree(Edge aPath[])
{
	int before,after;//before為前一個已訪問的點,after為下一個將要訪問的點
	int lowcost[20];//保存着未被訪問即(V-U)中編號為k的頂點到U中所有頂點的最小權值
	int closest[20];//保存着U中到V-U中編號為K的頂點權值最小的編號
	int used[20];//保存某點是否已經被訪問
	int min;

	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		lowcost[i] = graph.m_aAdjMatrix[0][i];//到i點的最小距離即為a點到i點的距離
		closest[i] = 0;//到i點最小距離的點是a點
		used[i] = 0;//所有點都未被訪問
	}
	used[0] = 1;//a點已被訪問
	before = 0;
	after = 0;
	for (int i = 0; i < graph.m_nVexNum - 1; i++)
	{

		min = 0xffff;

		for (int k = 1; k < graph.m_nVexNum; k++)
		{
			if (used[k] == 0 && lowcost[k] < min)
			{
				min = lowcost[k];
				after = k;
			}
		}
		cout << "before = " << before << "\tafter = " << after << endl;
		used[after] = 1;//j點已加入U集合
		aPath[i].vex1 = before;
		aPath[i].vex2 = after;
		aPath[i].weight = graph.m_aAdjMatrix[before][after];
		for (int j = 0; j < graph.m_nVexNum; j++)
		{
			for (int k = 0; k < graph.m_nVexNum; k++)
			{
				if ((used[j]==1)&&(used[k] == 0) && (graph.m_aAdjMatrix[j][k] < lowcost[k]))
				{
					lowcost[k] = graph.m_aAdjMatrix[j][k];
					closest[k] = after;
					before = j;
				}
			}
		}
	}

	for (int i = 0; i < graph.m_nVexNum - 1; i++)
	{
		cout << aPath[i].vex1 << " -> " << aPath[i].vex2 << "\t" << aPath[i].weight << endl;
	}
	int sum = 0;
	for (int i = 0; i < graph.m_nVexNum - 1; i++)
	{
		cout << graph.m_aVexs[aPath[i].vex1].name << " - " << graph.m_aVexs[aPath[i].vex2].name << "\t" << aPath[i].weight << endl;
		sum += aPath[i].weight;
	}
	cout << endl << endl << "pop stack!" << endl;

	return 0;
}
*/

int FindMinTree(Edge aPath[])
{
	int before, after;//before為前一個已訪問的點,after為下一個將要訪問的點
	int used[20];//保存某點是否已經被訪問
	int min;

	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		used[i] = 0;//所有點都未被訪問
	}
	used[0] = 1;//a點已被訪問
	before = 0;
	after = 0;
	for (int i = 0; i < graph.m_nVexNum - 1; i++)
	{
		min = 0xffff;
		for (int j = 0; j < graph.m_nVexNum; j++)
		{
			for (int k = 0; k < graph.m_nVexNum; k++)
			{
				if ((used[j] == 1) && (used[k] == 0) && (graph.m_aAdjMatrix[j][k] < min))
				{
					min = graph.m_aAdjMatrix[j][k];
					before = j;
					after = k;
				}
			}
		}
//		cout << i << "." << "before = " << before << "\tafter = " << after << endl;
		used[after] = 1;//j點已加入U集合
		aPath[i].vex1 = before;
		aPath[i].vex2 = after;
		aPath[i].weight = graph.m_aAdjMatrix[before][after];
	}
	return 0;
}

操作實現頭文件Tourism.h

#ifndef TOURISM_H
#define TOURISM_H

void CreateGraph(void);
void GetSpotInfo(void);
void TravelPath(void);
void FindShortPath(void);
void DesignPath(void);
#endif

操作實現源文件Tourism.cpp

#include"Tourism.h"
#include"Graph.h"
#include<iostream>
using namespace std;
extern Graph graph;
extern int EdgeNum;
extern Edge aEdge[100];

//extern bool isVisited[20];
#pragma warning (disable : 4996)


void CreateGraph(void)
{
	Init();
	FILE *fp = NULL;
	fp = fopen("Vex.txt", "r");
	if (!fp)
	{
		printf("Failed to open the file!");
		exit(-1);
	}
	int num;
	Vex sVex;
	fscanf(fp, "%d", &num);
	cout << "===== 創建景區景點圖 =====" << endl;
	cout << "頂點數目:" << num<<endl;
	cout << "----- 頂點 -----" << endl;
	for (int i = 0; i < num; i++)
	{
		fscanf(fp, "%d", &sVex.num);
		fscanf(fp, "%s", &sVex.name);
		fscanf(fp, "%s", &sVex.desc);
		cout << sVex.num << "-" << sVex.name << endl;
		InsertVex(sVex);
	}
	fclose(fp);
	fp = fopen("Edge.txt", "r");
	if (!fp)
	{
		printf("Failed to open this file!");
		exit(-1);
	}
	Edge sEdge;
	cout << "----- 邊 -----" << endl;
	EdgeNum = 0;
	while (!feof(fp))
	{
//		printf("!!!");
		fscanf(fp, "%d", &sEdge.vex1);
		fscanf(fp, "%d", &sEdge.vex2);
		fscanf(fp, "%d", &sEdge.weight);
		printf("<v%d,v%d> %d\n", sEdge.vex1, sEdge.vex2, sEdge.weight);
		InsertEdge(sEdge);
		aEdge[EdgeNum++] = sEdge;
	}
	fclose(fp);
	cout << endl << endl;
}


void GetSpotInfo(void)
{
	cout << "===== 查詢景點信息 =====" << endl;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		cout << graph.m_aVexs[i].num << "-" << graph.m_aVexs[i].name << endl;
	}
	int nVex;
	cout << "輸入想要查詢的景點編號: ";
	cin >> nVex;
	Vex sVex=GetVex(nVex);
	printf("%s\n%s\n", sVex.name,sVex.desc);
	cout << "----- 周邊景區 -----" << endl;
	int k = FindEdge(nVex, aEdge);
	for (int i = 0; i < k; i++)
	{
		cout << graph.m_aVexs[aEdge[i].vex1].name << "->" << graph.m_aVexs[aEdge[i].vex2].name << " " << aEdge[i].weight <<"m"<< endl;
	}
	cout << endl << endl;
}

void TravelPath(void)
{
	PathList pList;
	pList = (Path*)malloc(sizeof(Path));
	PathList PHead;
	PHead = pList;
//	pList->next = (Path*)malloc(sizeof(Path));
	cout << "===== 旅游景點導航 =====" << endl;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		cout << graph.m_aVexs[i].num << "-" << graph.m_aVexs[i].name << endl;
	}
	cout << "請輸入起始點編號:";
	int nVex;
	cin >> nVex;
	DFSTraverse(nVex, pList);
	cout << "導航路線為: " << endl;
//	cout << "路線1 : ";
//	cout<<graph.m_aVexs[nVex].name;
	pList = PHead;
	int i = 1;
	while (pList->next)
	{
		Vex sVex = GetVex(pList->vexs[0]);
		cout << "路線" << i++ << ":" << sVex.name;
		for (int j = 1; j<graph.m_nVexNum; j++)
		{
			printf(" -> %s", graph.m_aVexs[pList->vexs[j]].name);
//			sVex = GetVex(pList->vexs[j]);
//			cout << " -> " << sVex.name;
		}
		cout << endl;
		Path *temp = pList;
		pList = pList->next;
		free(temp);
	}
	free(pList);
	pList = NULL;
	PHead = NULL;
	cout << endl<<endl<<endl;
//	free(pList);
//	free(pList->next);
}

void FindShortPath(void)
{
	cout << "===== 搜索最短路徑 =====" << endl;
	for (int i = 0; i < graph.m_nVexNum; i++)
	{
		cout << graph.m_aVexs[i].num << "-" << graph.m_aVexs[i].name << endl;
	}
	int nVexStart;
	int nVexEnd;
	cout << "請輸入起點的編號: ";
	cin >> nVexStart;
	cout << "請輸入終點的編號: ";
	cin >> nVexEnd;
	Edge aPath[20];
	int nNum=FindShortPath(nVexStart, nVexEnd, aPath);
	Vex sVex = GetVex(aPath[0].vex1);
	int nLength = 0;
	cout << "最短路線為: ";
	cout << graph.m_aVexs[nVexStart].name;
	for (int i = 0; i < nNum-1; i++)
	{
		sVex = GetVex(aPath[i].vex2);
		cout << "->" << sVex.name;
		nLength += aPath[i].weight;
	}
	cout << endl;
	cout << "最短距離為: " << nLength << endl;
	cout << endl << endl;
}

void DesignPath(void)
{
	cout << "===== 鋪設電路規划 =====" << endl;
	cout << "在以下兩個景點之間鋪設電路:" << endl;
	Edge aPath[20];
	FindMinTree(aPath);
	int sum=0;
	for (int i = 0; i < graph.m_nVexNum - 1; i++)
	{
		cout << graph.m_aVexs[aPath[i].vex1].name << " - " << graph.m_aVexs[aPath[i].vex2].name << "\t" << aPath[i].weight << endl;
		sum += aPath[i].weight;
	}
	cout << "鋪設電路的總長度為:" << sum;
	cout << endl << endl << endl;
}

主函數源文件Main.cpp

#include<iostream>
#include"Tourism.h"
using namespace std;
#pragma warning( disable : 4996)

int main()
{
	while (true)
	{
		//輸出界面
		cout << "====景區信息管理系統====" << endl;
		cout << "1.創建景區景點圖" << endl;
		cout << "2.查詢景點信息" << endl;
		cout << "3.旅游景點導航" << endl;
		cout << "4.搜索最短路徑" << endl;
		cout << "5.鋪設電路規划" << endl;
		cout << "0.退出" << endl;
		int choice;
		cout << "請輸入操作編號<0~5>: ";
		cin >> choice;
		switch (choice)
		{
		case 1:
		{
			CreateGraph();
			break;
		}
		case 2:
		{
			GetSpotInfo();
			break;
		}
		case 3:
		{
			TravelPath();
			break;
		}
		case 4:
		{
			FindShortPath();
			break;
		}
		case 5:
		{
			DesignPath();
			break;
		}
		case 0:
		{
			cout << "退出系統!" << endl;
			exit(0);
		}
		default:
		{
			cout << "請輸入操作編號<0~5>: ";
			break;
		}
		}

	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM