图的应用——粗糙的校园导航系统

程序要求

校园导游咨询:编制一个为来访客人进行最短路径导游的程序。
基本要求:
(1)画出学校的校园平面图,所含景点不少于10个。以图中顶点表示校内各景点,存放名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
(2)为来访客人提供图中任意景点相关信息的查询。
(3)为来访客人提供图中任意景点的路径查询,即查询任意两个景点之间的一条最短的简单路径。

题目中涉及到的顶点名称以及对应的景点(电脑上的codeblocks编译环境不支持中文,因此景点名称使用英文)
顶点名称 中文名 英文名
0 the Second Gate of SWU
1 Garden of the Communist Youth League
2 Central Library
3 Zhuyuan Canteen
4 Xishi Street
5 No.25 Teaching Building
6 No.28 Teaching Building
7 The Statue of Chairman Mao
8 The First Playground
9 Tianjiabing
10 History Museum of SWU

算法分析

在本题目中,首先利用dest[][]数组存放景点信息,dest[][]数组为全局变量,这个二维数组可以看作很多名为dest[]的一维数组,用来存储景点的名称(字符串)。
创建校园景点的邻接矩阵。以顶点表示校内各景点,信息;以边表示路径,存放路径长度等相关信息。在CreateUDN函数中省去了输入边和权值的过程,而是直接对G.arcs[i][j].adj进行复制,i、j为顶点编号,一组i、i表示一条边,G.arcs[i][j].adj表示该边的权值,省略了邻接矩阵复杂的构造过程。同时从用户的角度而言,邻接矩阵的构建必然出现在使用此程序之前,不可能由用户来完成“对权值的输入”等过程。
利用迪杰斯特拉算法求从图的一个顶点找到到其余各个顶点的最短路径。迪杰斯特拉提出了一个按路径长度递增的次序,逐步产生最短路径的算法:
初使时令 S={V0},T={其余顶点},T中顶点对应的距离值,若存在<V0,Vi>,为<V0,Vi>弧上的权值,若不存在<V0,Vi>,为999。从T中选取一个其距离值为最小的顶点W,加入S,对T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值比不加W的路径要短,则修改此距离值。重复上述步骤,直到S中包含所有顶点,即S=V为止。
引进一个辅助向量D,它的每个分量D(i)表示当前所找到的从始点v0到每个终点vi的最短路径的长度。它的初态为:若从源点v0到vi有弧,则D[i]为弧上的权值;否则置D[i]为∞(程序中用最大正数MAXSIZE代表)。则长度为D[j]=min{D[i] | vi∈V-v0 } 的路径就是从v出发的长度最短的一条路径。
下一条长度次短的最短路径的长度必是:D[j]=Min{ D[ i ] | vi ∈ V-S}。其中,D[i]或者是弧(v0,vi )上的权值,或者是D[k](vk ∈ S)和弧(vk,vi)上的权值之和。 在每次求得一条最短路径之后,其终点vj加入集合S,然后对所有的vk ∈V-S,修改其D[k]: D[ k ] =Min { D[k], D[j]+arcs[j][k]},arcs[j][k]是弧(j,k)上的权值。
题目需要寻找任意两个景点之间的一条最短的简单路径,而不是从一个顶点出发到所有顶点的最短路径。在PrintShortestPath函数中,在已知起点和终点的情况下,由ShortestPath_DIJ函数已经得到了从起点到图中各个顶点的最短路径,然后将图中的各个顶点与终点参数作比较,如果某个顶点与终点参数相等,即G.vexs[i]==end,那么起点到终点的最短路径就是起点到G.vexs[i]的最短路径,将这个最短路径以及路径权值输出即可,而不用输出从起点到每个顶点的最短路径。
为来访客人提供图中任意景点相关信息的查询。游客输入的景点对应的信息(其名称)将被显示,方法是通过某一景点的序号,转化成在dest[][]函数中的位置,从而输出相对应的景点名称。

核心程序

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define MAX_VERTEX_NUM  20  //最大顶点个数
#define ERROR  -1
#define OK 1
#define TRUE 1
#define FALSE 0
//AdjMatrix [0][3]={6,NULL};AdjMatrix [1][3]={9,NULL};
typedef int VRType;//对带权图,则为权值类型。
typedef int Status;
typedef int InfoType;
typedef char VertexType;
typedef char Destinfo;
Destinfo dest[11][100]={"the second gate of SWU","garden of the communist youth league","Central Library","Zhuyuan Canteen","Xishi Street","No.25 teaching building","No.38 teaching building","The statue of Chairman Mao","The first playground","Tianjiabing","History Museum of SWU"};
//定义全局变量,二维数组用来存储景点名称,可以看作是11个数组名为dest[i]的一维数组
typedef struct ArcCell {
      VRType    adj;   //VRType是顶点关系类型。
                                   //对无权图,用1或0表示相邻否;
                                   //对带权图,则为权值类型。
      InfoType  *info;   //该弧相关信息的指针
}ArcCell,AdjMatrix [MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{
	VertexType  vexs[MAX_VERTEX_NUM]; //顶点向量
	AdjMatrix    arcs;    //邻接矩阵
	int        vexnum,arcnum;  //图的当前顶点数和弧数
}MGraph;

Status LocateVex(MGraph G,VertexType v)// 定位函数,参数为MGraph型变量G与VertexType型变量v,功能是找出顶点在数组G.vexs[i]中的位置{
{    int i;
    //printf("%c ",v);
    for(i=0;i<G.vexnum;i++)//从0开始到G.vexnum结束,若v的值等于G.vexs中第i个元素的值,那么v所处的位置就是G.vexs[i]在数组中所处的位置
    {
        if(v==G.vexs[i])
        {
            return i;
        }
    }

}

Status  PrintGraph(MGraph G)//输出函数,参数为MGraph型变量G,功能是打印邻接矩阵

{
    int i,j,k,p;
    printf("The vexs of the Graph:\n");
    for(i=0;i<G.vexnum;i++)
    {
        p=LocateVex(G,G.vexs[i]);
        printf("(%c)%s\n",G.vexs[i],dest[p]);
    }
    printf("The Matrix of the Graph\n");
    for(i=0;i<G.vexnum;i++)
    {
        for(j=0;j<G.vexnum;j++)
            printf("%5d ",G.arcs[i][j].adj);
        printf("\n");
    }



}


Status  CreateUDN(MGraph &G)//采用数组(邻接矩阵)表示法,构造无向网G,参数为MGraph 型变量G的引用。
{
    int i,j,k,IncInfo,w;
    char v1,v2,u;
    //char dest[11][100]={"the second gate of SWU","garden of the communist youth league","Central Library","Zhuyuan Canteen","Xishi Street","No.25 teaching building","No.38 teaching building","The statue of Chairman Mao","The first playground","Tianjiabing","History Museum of SWU"};
    i=0;
    for(i=0;i<11;i++)
        printf("%d------%s\n",i,dest[i]);
    //从键盘中输入一个无向网的顶点数目、边的数目、顶点信息(题目中为顶点名称)、
    //依附于两顶点的边以及它们的权值,输出打印无向网
    printf("Please input the num of destinations and arcs:\n");
    scanf("%d %d",&G.vexnum,&G.arcnum);
	//IncInfo为0则各弧不含其它信息
	 printf("Please enter %d vertices:",G.vexnum);
    for(i=0;i<G.vexnum;i++)
        scanf(" %c",&G.vexs[i]); //构造顶点向量
    for(i=0;i<G.vexnum;i++)    //初始化邻接矩阵
        for(j=0;j<G.vexnum;j++)
            G.arcs[i][j].adj=999;
    for(i=0;i<G.vexnum;i++)
        G.arcs[i][i].adj=0;
    G.arcs[0][2].adj=10;
    G.arcs[0][4].adj=30;
    G.arcs[0][5].adj=100;
    G.arcs[1][2].adj=5;
    G.arcs[2][3].adj=50;
    G.arcs[3][5].adj=10;
    G.arcs[4][5].adj=60;
G.arcs[4][3].adj=20;
//为了方便起见以及从面向客户的角度出发,将邻接矩阵的构建过程简化,省略了边(由两个顶点表示)以及权值的输入过程,而是直接对邻接矩阵中的adj赋值,如G.arcs[0][2].adj=10代表下标为0和2的顶点构成的边的权值为10,其他边和权值以此类推,这样做的好处是既是输入简化,通过将其转化为一个相对固定的模式,省略了邻接矩阵复杂的构造过程。同时从用户的角度而言,邻接矩阵的构建必然出现在使用此程序之前,不可能由用户来完成“对权值的输入”等过程。
   }

typedef VertexType PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix P,ShortPathTable D)
//用Dijstra算法求从图G的v0顶点到其余各个顶点v的最短路径
//P二维数组用于存放最短路径。每一行对应一个目标顶点,存放从v0到该顶点的最短路径顶点序列
//D数组用于存放到对应顶点的最短路径长度,每个目标顶点按顺序对应一个数组元素
//final[v]用于标识是否已经求得到顶点v的最短路径
{
	int v,w,i,j,min;
	int final[MAX_VERTEX_NUM];//final[v]用于标识是否已经求得到顶点v的最短路径
	for(v=0;v<G.vexnum ;++v)   //初始化
	{
		final[v]=FALSE;
		D[v]=G.arcs[v0][v].adj ;
		for(w=0;w<G.vexnum ;++w)
			P[v][w]=G.vexs [v0];       //初始化最短路径数组元素全部为起点v0
		if(D[v]<999) {P[v][1]=G.vexs [v];}   //如果从v0到v有边,则填入终点v到路径
	}
	D[v0]=0;
	final[v0]=TRUE;
	for(i=1;i<G.vexnum ;++i)
	{
		min=999;
		for(w=0;w<G.vexnum ;++w)         //选出从v0出发的最短路径(目标顶点对应final[w]=FALSE)
			if(!final[w])
				if(D[w]<min){v=w;min=D[w];}
		final[v]=TRUE;      //设置选出的最短路径目标顶点v对应final[v]为TRUE,表示已经选出
		for(w=0;w<G.vexnum ;++w)//更新到其余顶点的最短路径
			if(!final[w] && (min+G.arcs [v][w].adj <D[w]))  //如果v0-v的最短路径+v-w边的权值比v0-w的已知路径要短
			{
				D[w]=min+G.arcs[v][w].adj ;     //更新最短路径长度
				for(j=0;j<G.vexnum && P[v][j]!=G.vexs [v];j++)
					P[w][j]=P[v][j];   //将v0-v的最短路径先复制到w顶点对应行,以终点v做结束标值
				P[w][j]=G.vexs [v];     //v复制(前面循环里路径的最后一个顶点v没有复制)
				P[w][j+1]=G.vexs [w];  //添加终点w
			}
	}
}

void PrintShortestPath(MGraph G,int v0,PathMatrix P,ShortPathTable D,VertexType end)
//void PrintShortestPath(MGraph G,int v0,PathMatrix P,ShortPathTable D)
//输出显示从v0出发到end的最短路径以及经过的顶点,参数为图G,存放最短路径的数组P,存放到对应顶点的最短路径长度D以及起点v0终点end
{
	int i,j,p;
	//printf("\nThe shortest path from %c to other vertexs:\n",G.vexs[v0]);
	for(i=0;i<G.vexnum ;i++)
		if(v0!=i && D[i]!=999)
		{
		    if(G.vexs[i]==end)
			{
			    printf("\nThe shortest path from %c to %c:\n",G.vexs[v0],G.vexs[i]);
                printf("The length of the path:%d\n",D[i]);
                printf("path:");
                for(j=0;j<G.vexnum && P[i][j]!=G.vexs [i] ;j++)
                {
                    //p=(int)(P[i][j]-'0');
                    p=LocateVex(G,P[i][j]);//找到P[i][j]的位置
                    printf("%c(%s)->",P[i][j],dest[p]);//将P[i][j]对应的景点名称输出
                }
                //p=(int)(P[i][j]-'0');
                p=LocateVex(G,P[i][j]); //找到P[i][j]的位置
                printf("%c(%s)\n",P[i][j],dest[p]); //将P[i][j]对应的景点名称输出
			}
		}
}

int main()
{
    MGraph G;
	VertexType start,end;
	int v0,s,go[100],i;
	PathMatrix P;
	ShortPathTable D;
	CreateUDN(G);//构造邻接矩阵
	PrintGraph(G);//输出邻接矩阵
	printf("Please input the beginning:");
	getchar();
	scanf("%c",&start);//输入起点
	v0=LocateVex(G,start);
	if(v0==-1) exit(0);
	ShortestPath_DIJ(G,v0,P,D);
	printf("Please input the ending:");//输入终点
	getchar();
	scanf("%c",&end);
    printf("From %s to %s\n",dest[LocateVex(G,start)],dest[LocateVex(G,end)]);
	//PrintShortestPath(G,v0,P,D);
	PrintShortestPath(G,v0,P,D,end);//输出从起点到终点的最短路径
    printf("Learn more about our campus?please input!\n");
	getchar();
	scanf("%d",&s);
	go[0]=s;
	i=0;
	while(go[i]!=-1)
	{
        printf("(%d)%s\n",go[i],dest[go[i]]);
        i++;
        getchar();
        scanf("%d",&go[i]);


    }

}

实验结果

在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值