任务要求:
1. 设计数据结构,存储该导游图,只需存储各个景点的名称以及之间的距离即可(距离数据可以自己定,景点数量至少15个)
2. 输入一个起点景点,一个要前往的景点,输出最短路径。
3. 输入一个起点景点,设计一条合理旅游路线,游玩所有景点。(提示:可按照深度优先搜索算法,选择下一个景点的原则可以是离当前景点最近的没有去过的景点)
4. 输入一个起点景点,设计一条合理旅游路线,游玩用户指定的多个景点。
1.分析设计
(此处写程序的设计思路,流程图、接口设计、类定义等)
3.1.设计思路
- 设计数据结构:使用图的邻接矩阵表示法来存储景点之间的关系,定义顶点和边的结构。
- 实现算法:分别实现Dijkstra算法、DFS算法和Prime算法,用于寻找最优旅游路线。
- 用户交互:设计用户界面,接收用户输入,并调用相应的函数进行处理。
- 输出结果:根据用户需求,将最优旅游路线打印输出。
- 图的邻接矩阵表示法:使用二维数组来表示景点之间的关系,数组元素值表示两个景点之间的距离。
- 顶点结构定义:包含景点名称和编号等信息。
- 边的结构定义:包含起点、终点以及边的权重(距离)等信息。
3.2.流程图
三大算法流程图:
3.3.接口设计
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
3.4.类定义
- 主函数:规定系统的主要流程,接收用户输入并调用相应函数进行处理。
- Dijkstra算法函数:计算起点到其他景点的最短路径,并返回最优路径和距离。
- DFS算法函数:遍历图中的所有路径,并找出满足条件的最优路径。
- Prime算法函数:生成最小生成树,并返回最优路径和权重。
G->edges[a][b]的方式存储路径,以G->V[n].name的方式存储每一个游玩项目的名称,定义如下:
typedef struct VertexType{
char name[50];
}VertexType;
typedef struct graph{
VertexType V[16];
int edges[MAXVN][MAXVN];
int n,e;
}MGraph;
2.程序实现
(此处描述程序数据结构和核心算法的实现,遇到的主要问题及解决办法等。注意:不需要粘贴全部代码,只贴核心重要的部分;需要有必要的注释,不能只贴代码)
任务一图的存储方式为邻接矩阵,以G->edges[a][b]的方式存储路径,以G->V[n].name的方式存储每一个游玩项目的名称,定义如下:
typedef struct VertexType{
char name[50];
}VertexType;
typedef struct graph{
VertexType V[16];
int edges[MAXVN][MAXVN];
int n,e;
}MGraph;
任务二输入一个起点景点,一个要前往的景点,输出最短路径采用的是迪杰斯特拉算法求最短路径,将从起点开始出发每一个结点的上一步存储到path[]数组中,将起点到其余结点的路程存储到dis[]数组中,比较直达与经过一个结点后到达的路径长短,然后进行path[]与dis[]的改变。
void Dijkstra(MGraph *G,int start,int end)
{
int dis[MAXV];
int path[MAXV];
int s[MAXV];
int mindis;
int i,j,k;
for(i=1;i<=G->n;i++){
dis[i]=G->edges[start][i];
s[i]=0;
if(G->edges[start][i]<INF)
path[i]=start;
else
path[i]=-1;
}
s[start]=1;
for(i=1;i<=G->n;i++){
mindis=INF;
k=start;
for(j=1;j<=G->n;j++){
if(mindis>dis[j] &&s[j]==0){
mindis=dis[j];
k=j;
}
}
s[k]=1;
for(j=1;j<=G->n;j++){
if(dis[j]>dis[k]+G->edges[k][j]&&s[j]==0&&G->edges[k][j]<INF){
dis[j]=dis[k]+G->edges[k][j];
path[j]=k;
}
}
}
dispath(dis,path,s,G,start,end);
}
具体代码实现见课本,注:课本上的输出为%d<-%d<-…形式的,为了使其逆转,假设函数的定义为Dijkstra(MGraph *G,int start,int end)那么只需将输入编写如下,即可实现正序打印
printf("请输入起点景点和要前往的景点序号:");
scanf("%d %d",&end,&start);
Dijkstra(G,start,end);
任务三输入一个起点景点,设计一条合理旅游路线,游玩所有景点。
采用的是邻接矩阵的深度搜索遍历(这个实现方法简单而且大部分情况都是选择最近的景点作为下一步),不过值得注意的是要想完成多次的路线查询,需要在case2后面加一个for循环,将visited[]重新置为false,否则结果会出错
bool visited[MaxVertexNum];
void DFS(MGraph *G,int k){
printf("%s ",G->V[k].name);
visited[k]=true;
int i;
for(i=1;i<=G->n;i++){
if(G->edges[k][i]!=0&&G->edges[k][i]!=INF&&!visited[i])
DFS(G,i);
}
}
任务四输入一个起点景点,设计一条合理旅游路线,游玩用户指定的多个景点。这个任务采用的是prime算法最小生成树经过结点的打印,将起始节点和想要经过的结点复制到一个新的MGraph结构体中去,然后依次复制结点之间的路径,各个节点的名称,各个结点之间的路径需要用迪杰斯特拉算法依次生成使用的是
int djs(MGraph *G,int start,int end)(只是将迪杰斯特拉的输出改为dis[i]).
函数,最后打印出的是两结点的最短路径,然后再运用prime算法对新结构体中的数据进行处理
源代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXVN 100
#define MAXV 10010
#define max 1000
#define INF 32767
typedef enum {false, true} bool;
#define MaxVertexNum 20 /* 最大顶点数设为20*/
typedef struct VertexType{
char name[50];
}VertexType;
typedef struct graph{
VertexType V[20];
int edges[MAXVN][MAXVN];
int n,e;
}MGraph;
void menu() //菜单函数
{
printf(" ++++++++++++++++++++请选择++++++++++++++++++++\n");
printf(" 1.最短路径查询\n");
printf(" 2.旅游路线推荐\n");
printf(" 3.私人定制旅游路线\n");
printf(" 4.退出\n");
printf("+++++++++++++欢迎来到迪士尼乐园++++++++++++++\n");
printf("\n");
}
void creat(MGraph *G){
int i,j,k,n,e;
G->n=16;
G->e=20;
n=G->n;
e=G->e;
for(i=1;i<=n;i++){
for(j=i;j<=n;j++){
G->edges[i][j]=G->edges[j][i]=INF;
}
}
strcpy(G->V[1].name, "1.星球大战");
strcpy(G->V[2].name, "2.极速光轮");
strcpy(G->V[3].name, "3.星际营救");
strcpy(G->V[4].name, "4.太空幸会史迪奇");
strcpy(G->V[5].name, "5.喷气背包飞行");
strcpy(G->V[6].name, "6.小飞侠天空奇遇");
strcpy(G->V[7].name, "7.小飞条");
strcpy(G->V[8].name, "8.梦幻沙龙");
strcpy(G->V[9].name, "9.童话时光");
strcpy(G->V[10].name, "10.宴会厅");
strcpy(G->V[11].name, "11.晶彩奇航");
strcpy(G->V[12].name, "12.夜光幻影");
strcpy(G->V[13].name, "13.爱丽丝梦游仙境");
strcpy(G->V[14].name, "14.漫月轩");
strcpy(G->V[15].name, "15.七个小矮人过山车");
strcpy(G->V[16].name, "16.旋转木马");
G->edges[1][3]=10;
G->edges[1][2]=20;
G->edges[4][5]=10;
G->edges[3][4]=30;
G->edges[5][6]=30;
G->edges[5][7]=20;
G->edges[6][8]=10;
G->edges[8][9]=10;
G->edges[9][10]=10;
G->edges[8][10]=10;
G->edges[7][11]=20;
G->edges[10][12]=10;
G->edges[11][12]=10;
G->edges[10][13]=20;
G->edges[9][14]=30;
G->edges[12][15]=40;
G->edges[13][15]=20;
G->edges[14][15]=30;
G->edges[14][16]=30;
G->edges[9][16]=20;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
G->edges[j][i]=G->edges[i][j];
}
}
}
//深度优先设计旅游路线
bool visited[MaxVertexNum];
void DFS(MGraph *G,int k){
printf("%s ",G->V[k].name);
visited[k]=true;
int i;
for(i=1;i<=G->n;i++){
if(G->edges[k][i]!=0&&G->edges[k][i]!=INF&&!visited[i])
DFS(G,i);
}
}
//dijiesitra算法最短路径
void Dijkstra(MGraph *G,int start,int end)
{
int dis[MAXV];
int path[MAXV];
int s[MAXV];
int mindis;
int i,j,k;
for(i=1;i<=G->n;i++){
dis[i]=G->edges[start][i];
s[i]=0;
if(G->edges[start][i]<INF)
path[i]=start;
else
path[i]=-1;
}
s[start]=1;
for(i=1;i<=G->n;i++){
mindis=INF;
k=start;
for(j=1;j<=G->n;j++){
if(mindis>dis[j] &&s[j]==0){
mindis=dis[j];
k=j;
}
}
s[k]=1;
for(j=1;j<=G->n;j++){
if(dis[j]>dis[k]+G->edges[k][j]&&s[j]==0&&G->edges[k][j]<INF){
dis[j]=dis[k]+G->edges[k][j];
path[j]=k;
}
}
}
dispath(dis,path,s,G,start,end);
}
void dispath(int dis[],int path[],int s[],MGraph *G,int v,int e){
int i,k;
if(s[e]==1){
k=e;
printf("景点%d到景点%d的最短路径为:",e,v);
while(k!=v){
printf(" %s --> ",G->V[k].name);
k=path[k];
}
printf(" %s",G->V[v].name);
printf("\n总路程为%d",dis[e]);
}
else
printf("不存在路径");
}
int djs(MGraph *G,int start,int end)
{
int dis[MAXV];
int path[MAXV];
int s[MAXV];
int mindis;
int i,j,k;
for(i=1;i<=G->n;i++){
dis[i]=G->edges[start][i];
s[i]=0;
if(G->edges[start][i]<INF)
path[i]=start;
else
path[i]=-1;
}
s[start]=1;
for(i=1;i<=G->n;i++){
mindis=INF;
k=start;
for(j=1;j<=G->n;j++){
if(mindis>dis[j] &&s[j]==0){
mindis=dis[j];
k=j;
}
}
s[k]=1;
for(j=1;j<=G->n;j++){
if(dis[j]>dis[k]+G->edges[k][j]&&s[j]==0&&G->edges[k][j]<INF){
dis[j]=dis[k]+G->edges[k][j];
path[j]=k;
}
}
}
return dis[end];
}
void personal(MGraph *G,int start,int num){
int i,j,a,b;
MGraph *Q;
Q=(MGraph *)malloc(sizeof(MGraph));
for(i=1;i<=num+1;i++){
for(j=1;j<=num+1;j++){
Q->edges[i][j]=INF;
}}
Q->n=num+1;
Q->e=num*(num+1)/2;
int node[MAXVN];
node[1]=start;
printf("请输入经过的景点编号(不包含起始点):");
for(i=2;i<=Q->n;i++){
scanf("%d",&node[i]);
}
for(i=1;i<=Q->n;i++){
for(j=i;j<=Q->n;j++){
a=node[i];
b=node[j];
Q->edges[i][j]=Q->edges[j][i]=djs(G,a,b);
}
strcpy(Q->V[i].name,G->V[node[i]].name);
}
prime(Q,start,node);
}
void prime(MGraph* G,int v,int node[]) {
int visit[MAXVN]={0}; //点是否访问过,未访问0,访问1
visit[1] = 1; //起始点已经访问过
int short_length[MAXVN]; //访问过的点的集合到未访问过点的集合的最小路径
int m,i,j;
for (i = 1; i <= G->n; i++)
short_length[i] = G->edges[1][i]; //初始化,此时只有起始点
short_length[1] = 0; //起始点路径为0
printf("%s",G->V[1].name);
for (i = 1; i <G->n; i++)
{
int min_length = max;
int k=0;
for (j = 1; j <=G->n; j++) { //在所有未访问过的边里找到最短路径
if (min_length > short_length[j] && visit[j] == 0) {
k = j;
min_length = short_length[j];
}
}
visit[k] = 1;
printf("-->%s",G->V[k].name);
for (j = 1; j <= G->n; j++) {
if (visit[j] == 0 && short_length[j] > G->edges[k][j])
short_length[j] = G->edges[k][j];
}
}
return;
}
int main(){
MGraph *G;
int i,k;
int num;
int start,end;
int n,flag;
char a;
G=(MGraph *)malloc(sizeof(MGraph));
printf("\t\t\t迪士尼乐园游玩攻略\n");
float x,y,z;
for(y=1.5;y>-1.5;y-=0.1){
for(x=-1.5;x<1.5;x+=0.05){
z=x*x+y*y-1;
putchar(z*z*z-x*x*y*y*y <=0.0 ? '@' : ' ');
}
system("color 0c");
putchar('\n');
}
printf(" ");
printf("++++++++++++++++++++++++++++++++++++++\n");
printf("\t + +\n");
printf("\t + 欢迎来到迪士尼乐园 +\n");
printf("\t + +\n");
printf("\t + +\n");
printf("\t + 请按任意键跳转到菜单 +\n");
printf("\t + +\n");
printf("\t + 计科2202_郝雨川 +\n");
printf("\t ++++++++++++++++++++++++++++++++++++++\n");
getchar(); //等待用户输入任意键
system("cls");
system("color 07");
creat(G);
menu();
while(flag==0)
{
printf("请选择你需要操作的步骤(1--4):\n");
scanf("%d",&n);
if(n>=1&&n<=4)
{
flag=1;
}
else
{
flag=0;
printf("您输入有误,请重新选择!");
}
}
while(flag==1)
{
switch(n)
{
case 1:printf("最短路径查询\n");
printf("游玩项目序号(具体地图见大作业报告)\n1.星球大战\n2.极速光轮\n3.星际营救\n4.太空幸会史迪奇\n5.喷气背包飞行\n6.小飞侠天空奇遇\n7.小飞条\n8.梦幻沙龙\n9.童话时光\n10.宴会厅\n11.晶彩奇航\n12.夜光幻影\n13.爱丽丝梦游仙境\n14.漫月轩\n15七个小矮人过山车\n");
printf("请输入起点景点和要前往的景点序号:");
scanf("%d %d",&end,&start);
Dijkstra(G,start,end);
printf("\n");
break;
case 2:printf(" 游玩路线推荐\n");
int i;
for(i=1;i<=G->n;i++){
visited[i]=false;
}
printf("\n");
printf("游玩项目序号(具体地图见大作业报告)\n1.星球大战\n2.极速光轮\n3.星际营救\n4.太空幸会史迪奇\n5.喷气背包飞行\n6.小飞侠天空奇遇\n7.小飞条\n8.梦幻沙龙\n9.童话时光\n10.宴会厅\n11.晶彩奇航\n12.夜光幻影\n13.爱丽丝梦游仙境\n14.漫月轩\n15七个小矮人过山车\n");
printf("请输入你想最先游玩的项目序号:") ;
scanf("%d",&k);
printf("为您推荐的游玩路线为: ");
DFS(G,k);
break;
case 3:printf("私人定制路线\n");
printf("\n");
printf("游玩项目序号(具体地图见大作业报告)\n1.星球大战\n2.极速光轮\n3.星际营救\n4.太空幸会史迪奇\n5.喷气背包飞行\n6.小飞侠天空奇遇\n7.小飞条\n8.梦幻沙龙\n9.童话时光\n10.宴会厅\n11.晶彩奇航\n12.夜光幻影\n13.爱丽丝梦游仙境\n14.漫月轩\n15七个小矮人过山车\n");
printf("\n请输入起始景点编号:");
scanf("%d", &start);
printf("请输入要经过的景点数量(不包含起始点):");
scanf("%d", &num);
personal(G,start,num);
break;
case 4:exit(0);
break;
default:break;
}
getchar();
printf("\n");
printf("是否继续进行(y or n):\n");
scanf("%c",&a);
if(a=='y')
{
flag=1;
system("cls");
menu(); //调用菜单函数
printf("请再次选择你需要操作的步骤(1--4):\n");
scanf("%d",&n);
printf("\n");
}
else
exit(0);
}
}
运行结果展示:
开始界面:
最短路径查询:
旅游路线推荐:
私人定制旅游路线: