数据结构 实验 避暑山庄旅游路径规划项目

数据结构

实验 避暑山庄旅游路径规划项目

一、避暑山庄旅游路径规划项目的问题分析

 1. 旅游路径规划过程中经常遇到问题有哪些,具体到避暑山庄旅游路径规划中可能会有哪些问题,确认问题阶段;

(1).确定起点或终点的最短路径问题:即已知起点或终点,按照题目要求,求最短路径的问题。
(2).确定起点和终点的最短路径问题:即已知起点和终点,按照题目要求,求两点之间的最短路径。
(3).全局最短路径问题:按照题目要求,求图中所有的最短路径。

2.分解问题,写出问题陈述,即把问题分解为各个比较小的问题,区分出紧急、严重性或可能性等问题

(1).主页
(2).查看路线
(3).查找最短路径
(4).查找所有路径
(5).景点介绍
(6).景区地图
(7).退出

3. 分析选择关键活动,按照问题优先度排序,即制订研究这些问题的先后程序。

4. 分析此类问题所需数据的类型、特点、关系等。

地图数据常常可以用图(Graph)这类数据结构表示,那么在图结构中常用的搜索算法也可以应用到路径规划中

二、避暑山庄旅游路径规划项目的结构设计

1.根据问题分析设计一款合适的数据结构,如何抽象和存储地图?

用printf函数根据各个景点的大概位置存储、输出地图

2.选择合适存储结构方案,写出具体的结构体定义

Typedefstruct side{ //边的权值
int  wet; //权值
}side,wetmatrix[MaxNumber][MaxNumber]; //边的邻接矩阵类型
typedef struct vetinf {  //顶点信息
int number; //顶点编号
char name[64]; //顶点名称
char intro[256]; //顶点介绍
}vetinf;
typedef struct mapstr {  //图结构信息
vetinf vets[MaxNumber]; //顶点数组
wetmatrix mat; //邻接矩阵
int vetnum, sidenum;
}mapstr;

3.设计解决问题的基本功能/操作

1、图的初始化,由mapstr initmap()函数实现
2、查询景点在图中的序号,由int locatevet()函数实现
3、查询输入序号l,n间的长度不超过10个景点的路径,由void path()函数实现
4、查询两景点的所有路径,由int allpath()函数实现
5、迪杰斯特拉算法求单源最短路径,由void shortestpath()函数实现
6、主页,由void menu()函数实现
7、输出图的邻接矩阵的值,由void void printmapstr()函数实现
8、弗洛伊德算法,由void floyd()函数实现
9、输出数组,由void printarray()函数实现
10、输出最短路径,由void display()函数实现
11、任意两点间距离,由int shortdistance()函数实现
12、显示所有景点信息,由void compusinfor()函数实现
13、地图,由void schoolmap()函数实现
14、用户界面,由void mainwork()函数实现

三、代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Infinity 65535			//表示无穷大
#define MaxNumber 11			//用于邻接矩阵
#define vertex 9				//顶点个数
typedef struct side { 			//边的权值
	int wet;					//权值
}side, wetmatrix[MaxNumber][MaxNumber]; //边的邻接矩阵类型
typedef struct vetinf { 				//顶点信息
	int number;					//顶点编号
	char name[64];				//顶点名称
	char intro[256];			//顶点介绍
}vetinf;
typedef struct mapstr { 		//图结构信息
	vetinf vets[MaxNumber];		//顶点数组
	wetmatrix mat;				//邻接矩阵
	int vetnum, sidenum;
}mapstr;
//全局变量
mapstr campus;					//图结构变量(避暑山庄总览)
int d[30];
int visited[50];

int shortest[MaxNumber][MaxNumber];//定义全局变量存储最小路径
int pathh[MaxNumber][MaxNumber];//定义存储路径
//1.图的初始化
mapstr initmap() {
	mapstr m;//构件图m
	int i = 0, j = 0;
	m.vetnum = 9; //定义顶点个数
	m.sidenum = 11; //定义边的条数
	for (i = 1; i <= vertex; i++) //依次设置顶点信息
		m.vets[i].number = i;
	//输入顶点信息
	strcpy(m.vets[1].name, "松鹤斋");
	strcpy(m.vets[1].intro, "康熙时,皇太后来避暑山庄,居住在西峪的松鹤清樾。");
	strcpy(m.vets[2].name, "正宫");
	strcpy(m.vets[2].intro, "是宫殿区的主体建筑");
	strcpy(m.vets[3].name, "东宫");
	strcpy(m.vets[3].intro, "在松鹤斋的东面,地势比正宫和松鹤斋低。");
	strcpy(m.vets[4].name, "万壑松风殿");
	strcpy(m.vets[4].intro, "万壑松风的主殿。");
	strcpy(m.vets[5].name, "烟波致爽殿");
	strcpy(m.vets[5].intro, "是正宫后寝部分的主殿,也是清帝在山庄的寝宫");
	strcpy(m.vets[6].name, "外八庙");
	strcpy(m.vets[6].intro, "在避暑山庄的东面和北面,武烈河两岸和狮子沟北沿的山丘地带,共有11座寺院");
	strcpy(m.vets[7].name, "布达拉·行宫");
	strcpy(m.vets[7].intro, "坐落于避暑山庄正北狮子岭南麓,占地25.79万平方米");
	strcpy(m.vets[8].name, "普宁寺");
	strcpy(m.vets[8].intro, "坐落于避暑山庄东北部武烈河畔,占地5.78万平方米");
	strcpy(m.vets[9].name, "磬锤峰");
	strcpy(m.vets[9].intro, "坐落于避暑山庄东部,武烈河东岸,占地4005万平方米");
	for (i = 1; i <= vertex; i++)
		for (j = 1; j <= vertex; j++)
			m.mat[i][j].wet = Infinity; //初始化图的邻接矩阵
	m.mat[1][2].wet = 200;
	m.mat[1][3].wet = 150;
	m.mat[2][4].wet = 130;
	m.mat[3][6].wet = 200;
	m.mat[3][5].wet = 150;
	m.mat[4][6].wet = 100;
	m.mat[4][7].wet = 120;
	m.mat[5][8].wet = 100;
	m.mat[6][9].wet = 80;
	m.mat[7][9].wet = 120;
	m.mat[8][9].wet = 90;
	for (i = 1; i <= vertex; i++) //无向带权图是对称矩阵,给其另一半赋值
		for (j = 1; j <= vertex; j++)
			m.mat[j][i].wet = m.mat[i][j].wet;
	return m;
}

//2.查询景点在图中的序号
int locatevet(mapstr m, int v) {
	int i;
	for (i = 0; i <= m.vetnum; i++)
		if (v == m.vets[i].number)
			return i;//找到返回顶点i
	return -1;//未找到
}

//3.查询输入序号l,n间的长度不超过10个景点的路径
void path(mapstr m, int l, int n, int k) {
	int s, t = k + 1;
	int length = 0; //t用于存储路径上下一顶点对应的d[]数组元素的下标
	if (d[k] == n && k < 8) { //若d[k]是终点且景点个数<8,则输出该路径
		for (s = 0; s < k; s++) {
			length = length + m.mat[d[s]][d[s + 1]].wet;
		}
		if (length < 200) { //打印路径小于200(定长)的路径
			for (s = 0; s < k; s++) { //输出该路径,s=0时为起点m
				printf("%d%s--->", d[s], m.vets[d[s]].name);
			}
			printf("%d%s  ", d[s], m.vets[d[s]].name); //输出最后一个顶点
			printf("总路线长为%d米\n\n", length);
		}
	} else {
		s = 1;
		while (s <= m.vetnum) { //从第m个顶点,访问所有顶点是否有路径
			if ((m.mat[d[k]][s].wet < Infinity) && (visited[s] == 0)) { //顶点有边且未被访问
				visited[s] = 1;
				d[k + 1] = s; //存储顶点编号
				path(m, l, n, t);
				visited[s] = 0; //将找到的路径上的顶点的访问标志重新设置为,便于探究新的路径
			}
			s++;//试验下一顶点s开始是否有到终点的路径;
		}
	}
}

//4.查询两景点的所有路径
int allpath(mapstr m) {
	int k, i, j, l, n;
	printf("\n\n请输入您想要查询的两个景点的编号:");
	scanf("%d %d", &i, &j);
	printf("\n\n");
	l = locatevet(m, i); //locatevet 确定该顶点是否存在。若存在,返回该顶点编号。
	n = locatevet(m, j);
	d[0] = l; //路径起点l(字母).(d[]数组为全局变量)
	for (k = 0; k < vertex; k++)
		visited[k] = 0;
	visited[l] = 1;
	path(m, l, n, 0);
	return 1;
}

//5.迪杰斯特拉算法求单源最短路径
void shortestpath(mapstr m) {
	int v0, v, w, k = 1, min, t, p;
	int final[MaxNumber];//final[w]=1表示已经求得顶点V0到Vw的的最短路径
	int Pathside[MaxNumber];//用于存储最短路径下标的数组
	int ShortPathwet[MaxNumber];//用于存储到各点最短路径的权值和
	printf("\n请输入起始景点的编号:");
	scanf("%d", &v0);
	printf("\n\n");
	while (v0 < 0 || v0 > vertex) { //判断是否输入正确
		printf("\n您输入的景点编号不存在\n");
		printf("请重新输入:");
		scanf("%d", &v0);
	}
	for (v = 1; v <= m.vetnum; v++) { //数组初始化
		final[v] = 0; //全部顶点初始化为未找到路径
		ShortPathwet[v] = m.mat[v0][v].wet; //将与v0有连线的路径加上权值
		Pathside[v] = 0; //初始化路径数组为0
	}
	ShortPathwet[v0] = 0;
	final[v0] = 1;
	//Dijkstr算法主体
	for (v = 1; v <= m.vetnum; v++) {
		min = Infinity;
		for (w = 1; w <= m.vetnum; w++) { //找出离当前指向顶点最近的点
			if (!final[w] && ShortPathwet[w] < min) { //未被访问且存在边
				k = w;
				min = ShortPathwet[w];
			}
		}
		final[k] = 1; //将找到的离当前顶点最近的置1
		//修正
		for (w = 1; w <= m.vetnum; w++) {
			if (!final[w] && (min + m.mat[k][w].wet < ShortPathwet[w])) {
				ShortPathwet[w] = min + m.mat[k][w].wet; //修改当前最优路径长度
				Pathside[w] = k; //存放前驱结点
			}
		}
	}
	printf("打印P数组:");	 //打印p数组
	for (t = 1; t <= m.vetnum; t++) {
		printf("%d ", Pathside[t]);
	}
	printf("\n\n");
	printf("打印S数组:");	 //打印s数组
	for (t = 1; t <= m.vetnum; t++) {
		printf("%d ", ShortPathwet[t]);
	}
	printf("\n\n");
	//打印最短路径
	for (t = 1; t <= m.vetnum; t++) {
		p = t;
		if (t != v0) {
			printf("%d%s", t, m.vets[t].name);
			for (w = 1; w <= m.vetnum; w++) {
				if (Pathside[p] != 0) {
					printf("<--%d%s", Pathside[p], m.vets[p].name);
					p = Pathside[p];
				}
			}
			printf("<--%d%s", v0, m.vets[v0].name);
			printf("\n总路线长为%d米\n\n", ShortPathwet[t]);
		}
	}
}

//6.主页
void menu() {
	printf(" │                    承德避暑山庄                      │\n");
	printf(" │                     菜 单 选 择                      │\n");
	printf(" │  ****************************************************│\n");
	printf(" │  ******************1.主页****************************│\n");
	printf(" │  ******************2.查看游览路线 *******************│\n");
	printf(" │  ******************3.查询景点间最短路径**************│\n");
	printf(" │  ******************4.查询景点间所有路径**************│\n");
	printf(" │  ******************5.景点介绍************************│\n");
	printf(" │  ******************6.景区地图************************│\n");
	printf(" │  ******************0.退出****************************│\n");
	printf(" │  *************************************************** │\n");
}


//7.输出图的邻接矩阵的值
void printmapstr(mapstr m) {
	int i, j, k = 0;
	for (i = 1; i <= vertex; i++) {
		if (m.vets[i].number != -1)
			printf("%6d", i);
	}
	printf("\n");
	for (i = 1; i <= m.vetnum; i++) {
		for (j = 1; j <= m.vetnum; j++) {
			if (m.mat[i][j].wet == Infinity)
				printf(" **** ");
			else
				printf("%6d", m.mat[i][j].wet);
			k++;
			if (k % m.vetnum == 0)
				printf("\n");
		}
	}
}



//8.弗洛伊德算法
void floyd(mapstr m) {
	int i, j, k;
	for (i = 1; i <= vertex; i++) { //将图的邻接矩阵赋值给 shortest二维数组,将矩阵pathh全部初始化为-1
		for (j = 1; j <= vertex; j++) {
			shortest[i][j] = m.mat[i][j].wet;
			pathh[i][j] = j;
		}
	}
	int ii, jj, k1 = 0;
	for (ii = 1; ii <= vertex; ii++)
		printf("%6d", ii); //横着标号1到11
	printf("\n");
	for (ii = 1; ii <= vertex; ii++) {
		printf("%d", ii);
		for (jj = 1; jj <= vertex; jj++) {
			printf("%6d", pathh[ii][jj]);
			k1++;
			if (k1 % vertex == 0)
				printf("\n");
		}
	}
	printf("\n\n\n");
	for (k = 1; k <= vertex; k++) { //核心操作,完成了以k为中间点对所有的顶点对(i,j)进行检测和修改
		for (i = 1; i <= vertex; i++) {
			for (j = 1; j <= vertex; j++) {
				if (shortest[i][j] > shortest[i][k] + shortest[k][j]) {
					shortest[i][j] = shortest[i][k] + shortest[k][j];
					pathh[i][j] = pathh[i][k]; //记录一下所走的路 //P数组用来存放前驱顶点
				}
			}
		}
	}
}

//9.输出数组
void printarray() {
	int i, j, k = 0;
	for (i = 1; i <= vertex; i++)
		printf("%6d", i); //横着标号0-11
	printf("\n");
	for (i = 0; i <= vertex; i++) {
		printf("%d", i); //竖着标号0-11
		for (j = 1; j <= vertex; j++) {
			printf("%6d", pathh[i][j]);
			k++;
			if (k % vertex == 0)
				printf("\n");
		}
	}
	printf("\n\n\n");
}

//10.输出最短路径
void display(mapstr m, int i, int j) {
	int a, b;
	a = i, b = j;
	printf("您要查询的两景点间最短路径:\n\n");
	printf("%d%s", a, m.vets[a].name);
	while (pathh[i][j] != b) {
		printf("-->%d%s", pathh[i][j], m.vets[pathh[i][j]].name);
		i = pathh[i][j];
	}
	printf("-->%d%s\n\n", b, m.vets[b].name);
	printf("%s-->%s的最短路径是:%d米\n\n", m.vets[a].name, m.vets[b].name, shortest[a][b]);
}

//11任意两点间距离(16-19)
int shortdistance(mapstr m) {
	int i, j;
	printf("请输入要查询的两个景点的数字编号(用空格隔开)\n");
	scanf("%d %d", &i, &j);
	if (i < 0 || i > vertex || j < 0 || j > vertex) {
		printf("输入信息有误!\n\n");
		printf("请输入要查询的两个景点的数字编号(用空格隔开)\n");
		scanf("%d %d", &i, &j);
	} else {
		floyd(m);
		printarray();
		display(m, i, j);
	}
	return 1;
}

//12显示所有景点信息
void compusinfor(mapstr m) {
	int i;
	printf(" \n\n编号     景点名称                        简介\n");
	printf("*************************************************************************\n");
	for (i = 1; i <= vertex; i++) {
		if (m.vets[i].number != -1)
			printf("%-10d%-25s%-70s\n", m.vets[i].number, m.vets[i].name, m.vets[i].intro);
	}
	printf("*************************************************************************\n");
}

//13地图
void schoolmap() {
	printf(" ---------------------------------承德避暑山庄地图----------------------------------------------\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````南山积雪````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("``````````````````````````````````````````````````````````````````````````````陆合塔````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("`````````````````````````````````````````````````文津阁`````````````````````````````````````````\n");
	printf("``````四面云山``````````````````````````````````````````````````````````````````万树园``````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````芳园居`````````````````月色江声`````````````````````````````````\n");
	printf("```````````````````````````````环碧`````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("``````````````````````````````水心檞````````````````````````````````````````````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("``````````````````正宫````````````````````````````````````````````文园狮子林````````````````````\n");
	printf("````````````````````````````````````````````````````````````````````````````````````````````````\n");
	printf("```````````````````丽正门``````````````````````````````德汇门```````````````````````````````````\n");
	printf("\n\n");
	printf("\n 																		西<---|--->东     \n");
}

//14用户界面
void mainwork() {
	menu();
	int choice;
	campus = initmap();
	do {
		printf("请输入你的选择:");
		scanf("%d", &choice);
		switch (choice) {
			case 1:
				menu();
				break;
			case 2:
				shortestpath(campus);
				break;
			case 3:
				shortdistance(campus);
				break;
			case 4:
				allpath(campus);
				break;
			case 5:
				compusinfor(campus);
				break;
			case 6:
				schoolmap();
				break;
			case 0:
				printf("谢谢使用\n");
				break;
			default:
				printf("未找到该功能,请输入有效选项!\n");
				break;
		}
	} while (choice);
}

int main() {
	mainwork();
	return 0;
}

四、实验结果

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>旅游主页面</title> <style> body { margin: 0; padding: 0; font-family: Arial, sans-serif; } header { background-color: #333; color: #fff; padding: 20px; text-align: center; } nav { background-color: #4CAF50; overflow: hidden; } nav a { float: left; color: #fff; text-align: center; padding: 14px 16px; text-decoration: none; font-size: 17px; } nav a:hover { background-color: #ddd; color: #333; } section { margin: 20px 0; padding: 20px; background-color: #f2f2f2; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; } section div { width: 30%; background-color: #fff; padding: 20px; margin-bottom: 20px; border-radius: 10px; box-shadow: 0 5px 10px rgba(0,0,0,0.3); transition: transform 0.3s ease-in-out; } section div:hover { transform: translateY(-10px); } section div img { width: 100%; height: 200px; object-fit: cover; border-radius: 10px; margin-bottom: 10px; } section div h3 { font-size: 20px; margin-bottom: 10px; color: #333; } section div p { font-size: 16px; line-height: 1.5; color: #666; } aside { background-color: #ddd; padding: 20px; text-align: center; } aside h3 { font-size: 24px; margin-bottom: 10px; color: #333; } aside p { font-size: 16px; line-height: 1.5; color: #666; } footer { background-color: #333; color: #fff; padding: 20px; text-align: center; } @media screen and (max-width: 768px) { section div { width: 45%; } } @media screen and (max-width: 480px) { section div { width: 100%; } } </style> </head> <body> <header> <h1>旅游主页面</h1> </header> <nav> <a href="#">首页</a> <a href="#">国内旅游</a> <a href="#">出境旅游</a> <a href="#">特价旅游</a> <a href="#">自由行</a> <a href="#">邮轮旅游</a> <a href="#">旅游攻略</a> <a href="#">关于我们</a> </nav> <section> <div> <img src="https://picsum.photos/id/1015/400/300" alt=""> <h3>泰国普吉岛五日游</h3> <p>景点:普吉岛西海岸、芭东海滩、斯米兰岛、神仙半岛、卡伦海滩</p> <p>价格:¥3999起</p> <a href="#">查看详情</a> </div> <div> <img src="https://picsum.photos/id/1018/400/300" alt=""> <h3>日本东京六日游</h3> <p>景点:上野公园、淺草寺、涉谷、新宿、迪士尼乐园</p> <p>价格:¥6999起</p> <a href="#">查看详情</a> </div> <div> <img src="https://picsum.photos/id/1020/400/300" alt=""> <h3>美国洛杉矶七日游</h3> <p>景点:环球影城、好莱坞、比佛利山庄、圣塔莫尼卡海滩、自由女神像</p> <p>价格:¥8999起</p> <a href="#">查看详情</a> </div> <div> <img src="https://picsum.photos/id/1022/400/300" alt=""> <h3>澳大利亚悉尼十日游</h3> <p>景点:歌剧院、悉尼大桥、蓝山、达令港、海滩</p> <p>价格:¥12999起</p> <a href="#">查看详情</a> </div> <div> <img src="https://picsum.photos/id/1024/400/300" alt=""> <h3>马尔代夫度假</h3> <p>景点:沙滩、海水浴、潜水、喷泉、水疗</p> <p>价格:¥18999起</p> <a href="#">查看详情</a> </div> <div> <img src="https://picsum.photos/id/1025/400/300" alt=""> <h3>新西兰南岛十五日游</h3> <p>景点:基督城、皇后镇、米尔福德峡湾、弗朗茨约瑟夫冰川、凯库拉</p> <p>价格:¥16999起</p> <a href="#">查看详情</a> </div> </section> <aside> <h3>热门旅游推荐</h3> <p>1. 泰国普吉岛五日游</p> <p>2. 日本东京六日游</p> <p>3. 美国洛杉矶七日游</p> <p>4. 澳大利亚悉尼十日游</p> <p>5. 马尔代夫度假</p> <p>6. 新西兰南岛十五日游</p> </aside> <footer> <p>© 2021 旅游主页面</p> </footer> </body> </html>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值