#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define INFINITY 32768 //无穷大
#define MAX_VERTEX_NUM 11 //最大顶点数
typedef struct ArCell
{
int adj; //路径长度,对于无权图0-1-表示是否相邻,对于带权图则为权值
}ArCell;
typedef struct //图中顶点表示主要景点,存放景点的编号、名称、简介等信息,
{
char name[30]; //名称
int num; //编号
char introduction[100];//简介
}VertexDat; // 定义顶点的类型
typedef struct
{
VertexDat vexs[MAX_VERTEX_NUM]; //顶点数组
ArCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵
int vexnum,arcnum; //顶点数,边数
}MGraph;//图的类型
MGraph *G; //图的类型,全局变量
/* 图的创建算法
输入顶点和边数,建立for循环输入景点编号,名称,简介,然后输入相邻景点的权值
并赋值给邻接矩阵所指的权值
*/
MGraph *CreatUDN(MGraph *G)//初始化图形,接受用户输入
{
int i,j,k,w;//i,j,k,w全为循环变量
char s[10] = "A";
#if 0
printf("请输入图的顶点数,弧数:");
scanf("%d%d",&G->vexnum,&G->arcnum); //输入顶点和边数
printf("请输入景点的编号:、名称、简介:\n"); //输入景点编号,名称,简介
for(i=1;i<=G->vexnum;i++)
{
printf("景点编号:");
scanf("%d",&G->vexs[i].num);
printf("景点名称:");
scanf("%s",G->vexs[i].name);
printf("景点简介:");
scanf("%s",G->vexs[i].introduction);
}
for(i=1;i<=G->vexnum;i++)
for(j=1;j<=G->vexnum;j++)
G->arcs[i][j].adj=INFINITY;
printf("请输入路径长度:\n"); //输入权值(路径长度)
for(k=1;k<=G->arcnum;k++)
{
printf("第%d条边:\n",k);
printf("景点对(i,j):"); //输入相邻景点
scanf("%d",&i);
scanf("%d",&j);
printf("路径长度:"); //输入相邻景点的权值
scanf("%d",&w);
G->arcs[i][j].adj=w; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];// 下边是可直接到达的景点间的距离,由于两个景点间距离是互相的,
// 所以要对图中对称的边同时赋值。
}
#else
G->vexnum = 6;
G->arcnum = 14;
for(i=1;i<=G->vexnum;i++)
{
G->vexs[i].num = i;
strcpy(G->vexs[i].name, s);
strcpy(G->vexs[i].introduction, s);
*s += 1;
}
for(i=1;i<=G->vexnum;i++)
for(j=1;j<=G->vexnum;j++)
G->arcs[i][j].adj=INFINITY;
i = 1;j=2;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];// 下边是可直接到达的景点间的距离,由于两个景点间距离是互相的,
// 所以要对图中对称的边同时赋值。
i = 2;j=1;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 1;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 3;j=1;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 2;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 3;j=2;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 3;j=4;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 4;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 3;j=5;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 5;j=3;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 4;j=6;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 6;j=4;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 5;j=6;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
i = 6;j=5;
G->arcs[i][j].adj=1; //把权值赋值给无向图G所指的邻接矩阵所指的权值
G->arcs[j][i]=G->arcs[i][j];
#endif
printf("\t创建完毕!\n");
return G;
}
/* 两点之间最短路径算法(迪杰斯特拉算法)
1.将v0到其余顶点的最短路径长度初始化为权值: Dist[i]=G->arcs[v0][vi].adj;{vi属于V-S}
2.选择vk,使得Dist[i]=min(Dist[i]|vi属于V-S)
vk为目前求的下一条从v0出发的最短路径的终点
3.将vk加入S
4.修正从v0出发到集合V-S的任一顶点vi的最短路径的长度:从v0出发到集合V-S上任一顶点vi的当前最短路径长度为Dist[i]
从v0出发,中间经过新加入S的vk,然后到达集合V-S上任一顶点vi的路径长度为:
Dist[k]+G->arcs[v][w].adj
如果Dist[k]+G->arcs[v][w].adj<Dist[i]
Dist[i]=Dist[k]+G->arcs[k][i].adj;
重复n-1次即可求出v0到其余顶点的最短路径
算法的时间复杂度为O(n*n).
*/
long int Dist[MAX_VERTEX_NUM]; // 辅助变量存储最短路径长度
int p[MAX_VERTEX_NUM ][MAX_VERTEX_NUM]; //起点到终点的路径数组
void ShortestPath_DIJ(MGraph *G,int v0)// 迪杰斯特拉算法来计算出起点到终点之间的最短路径,v0为起点
{
int v,w,i,min,x; //v,w,i,x为循环变量,min为最短长度
int path[MAX_VERTEX_NUM]; //存放最短路径
for(v=1;v<=G->vexnum;v++)
{
path[v]=0; //假设从顶点v0到顶点v没有最短路径
Dist[v]=G->arcs[v0][v].adj; //将与之相关的权值放入D中存放
for(w=1;w<=G->vexnum;w++)
p[v][w]=0; //设置为空路径
if(Dist[v]<INFINITY) //存在路径
{
p[v][v0]=1; //存在标志置为一
p[v][v]=1; //自身到自身
}
}
Dist[v0]=0;
path[v0]=1; //初始化v0顶点属于S集合
for(i=1;i<=G->vexnum;i++) //开始主循环,每一次求得v0到某个顶点的最短路径,并将其加入到S集合
{
min=INFINITY; //当前所知离顶点v0的最近距离
for(w=1;w<=G->vexnum;w++)
if(!path[w]) //w顶点在v-s中
if(Dist[w]<min) //w顶点离v0顶点更近
{
v=w;
min=Dist[w];//最短长度给min
}
path[v]=1; //离v0顶点更近的v加入到s集合
for(w=1;w<=G->vexnum;w++)
if(!path[w]&&(min+G->arcs[v][w].adj<Dist[w]))//更新当前最短路径及其距离
{
Dist[w]=min+G->arcs[v][w].adj; // 不在s集合,并且比以前所找到的路径都短就更新当前路径
for(x=1;x<=G->vexnum;x++)
p[w][x]=p[v][x];
p[w][w]=1;
}
}
}//ShortestPath_DIJ end
void output(int sight1,int sight2) // 输出函数
{
int a,b,c,d,q=0;
a=sight2; /* 将景点二赋值给a */
if(a!=sight1) /* 如果景点二不和景点一输入重合,则进行... */
{
printf("\n\t从%s到%s的最短路径是",G->vexs[sight1].name,G->vexs[sight2].name);/* 输出提示信息 */
printf("\t(最短距离为 %dm.)\n\n\t",Dist[a]); /* 输出sight1到sight2的最短路径长度,存放在D[]数组中 */
printf("\t%s",G->vexs[sight1].name); /* 输出景点一的名称 */
d=sight1; /* 将景点一的编号赋值给d */
for(c=1;c<=MAX_VERTEX_NUM;c++)
{
gate:; /* 标号,可以作为goto语句跳转的位置 */
p[a][sight1]=0;
for(b=1;b<=MAX_VERTEX_NUM;b++)
{
if(G->arcs[d][b].adj<INFINITY&&p[a][b]) /* 如果景点一和它的一个临界点之间存在路径且最短路径 */
{
printf("-->%s",G->vexs[b].name); /* 输出此节点的名称 */
p[a][b]=0;
d=b; /* 将b作为出发点进行下一次循环输出,如此反复 */
goto gate;
}
}
}
}
}
int FindInformation(MGraph *G,char a[])// 查询各景点的相关信息
{
int i;
for(i=1;i<=G->vexnum;i++)
{
if(strcmp(G->vexs[i].name,a)==0)
break;
}
if(i==(G->vexnum+1))
{
return -1;
}
else
return G->vexs[i].num;
}
void Floyd(MGraph *G)
{
int v,u,i,w,k,j=0,flag=1,p[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM],D[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
char A[10],B[10];
for(v=1;v<=G->vexnum;v++)
for(w=1;w<=G->vexnum;w++)
{
D[v][w]=G->arcs[v][w].adj;
for(u=1;u<=G->vexnum;u++)
p[v][w][u]=0;
if(D[v][w]<INFINITY)
{
p[v][w][v]=1;p[v][w][w]=1;
}
}
for(u=1;u<=G->vexnum;u++)
for(v=1;v<=G->vexnum;v++)
for(w=1;w<=G->vexnum;w++)
if(D[v][u]+D[u][w]<D[v][w])
{
D[v][w]=D[v][u]+D[u][w];
for(i=1;i<=G->vexnum;i++)
p[v][w][i]=p[v][u][i]||p[u][w][i];
}
printf("\t请输入起点的景点名称:\n");
scanf("%s",&A);
k=FindInformation(G,A);
if(k==-1){
printf("\t景点不存在!\n");
return ;
}
printf("\t请输入终点的景点名称:\n");
scanf("%s",&B);
k=FindInformation(G,B);
if(j==-1){
printf("\t景点不存在!\n");
return ;
}
printf("%s",G->vexs[k].name);
for(u=1;u<=G->vexnum;u++)
if(p[k][j][u]&&k!=u&&j!=u)
printf("-->%s",G->vexs[u].name);
printf("-->%s",G->vexs[j].name);
printf(" 总路线长%dm\n",D[k][j]);
}//Floyd end
int a=0;/*全局变量,用来记录每对顶点之间的所有路径的条数*/
int visited[MAX_VERTEX_NUM];/*全局数组,用来记录各顶点被访问的情况*/
int v[MAX_VERTEX_NUM];/*全局数组,用来存放路径上的各顶点*/
void path(MGraph *G,int i,int j,int k)
/*确定路径上第k+1个顶点的序号*/
{int s;
if(v[k]==j)/*找到一条路径*/
{
a++;/*路径的条数值加1*/
printf("第%d条:",a);
for(s=1;s<k;s++)/*输出一条路径*/
printf("%s->",G->vexs[v[s]].name);
printf("%s\n",G->vexs[v[s]].name);
}
s=1;
while(s<=G->vexnum)
{if(s!=i)/*保证找到的是简单路径*/
{
if(G->arcs[v[k]][s].adj!=INFINITY&&visited[s]==0)
/*当vk与vs之间有边存在且vs未被访问过*/
{visited[s]=1;/*置访问标志位为1,即已访问的*/
v[k+1]=s;/*将顶点s加入到v数组中*/
path(G,i,j,k+1);/*递归调用之*/
visited[s]=0;/*重置访问标志位为0,即未访问的,以便该顶点能被重新使用*/
}}
s++;
}
}
void disppath(MGraph *G,int i,int j)
{
int k;
v[1]=i;
for(k=1;k<=G->vexnum;k++)
visited[i]=0;/*初始化各顶点的访问标志位,即都为未访问过的*/
a=0;/*初始化路径的条数*/
path(G,i,j,1);/*通过调用path函数,找到从vi到vj的所有路径并输出*/
}
void SearchAllpath(MGraph *G)/*查询两个景点间的所有路径*/
{ int i,j;
char b[10],c[10];
printf("请输入源点景点名称:");
scanf("%s",&b);
i=FindInformation(G,b);
getchar();
if(i==-1)
{
printf("你输入的源点景点名称不存在!\n");
return;
}
printf("请输入终点景点名称:");
scanf("%s",&c);
j=FindInformation(G,c);
getchar();
if(j==-1)
{
printf("你输入的终点景点名称不存在!\n");
return;
}
printf("从%s到%s的所有游览路径有:\n",G->vexs[i].name,G->vexs[j].name);/*输出出发景点和目地景点的名称*/
disppath(G,i,j);/*调用disppath函数,用来输出两个景点间的所有路径*/
}
char SearchMenu() /* 查询子菜单 */
{
char c;
int flag;
do{
flag=1;
system("cls");
printf("\n\t\t┏━━━━━━━━━━━━━━━┑\n");
printf("\t\t\t┃ ┃\n");
printf("\t\t\t┃ 1、按照景点编号查询 ┃\n");
printf("\t\t\t┃ 2、按照景点名称查询 ┃\n");
printf("\t\t\t┃ 0、返回 ┃\n");
printf("\t\t\t┃ ┃\n");
printf("\t\t\t┗━━━━━━━━━━━━━━━┛\n");
printf("\t\t\t\t请输入您的选择:");
scanf("%c",&c);
if(c=='1'||c=='2'||c=='0')
flag=0;
}while(flag);
return c;
}
void search(MGraph *G) /* 查询景点信息 */
{
int num;
int i;
char c;
char name[20];
do
{
system("cls");
c=SearchMenu();
switch (c)
{
case '1':
system("cls");
printf("\n\n\t\t请输入您要查找的景点编号:");
scanf("%d",&num);
for(i=1;i<=MAX_VERTEX_NUM;i++)
{
if(num==G->vexs[i].num)
{
printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓\n");
printf("┃编号┃景点名称 ┃简介 ┃\n");
printf("┃%-4d %-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛\n");
printf("\n\t\t\t按任意键返回...");
getchar();
getchar();
break;
}
}
if(i==MAX_VERTEX_NUM)
{
printf("\n\n\t\t\t没有找到!");
printf("\n\n\t\t\t按任意键返回...");
getchar();
getchar();
}
break;
case '2':
system("cls");
printf("\n\n\t\t请输入您要查找的景点名称:");
scanf("%s",&name);
for(i=1;i<=MAX_VERTEX_NUM;i++)
{
if(!strcmp(name,G->vexs[i].name))
{
printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓\n");
printf("┃编号┃景点名称 ┃简介 ┃\n");
printf("┃%-4d %-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛\n");
printf("\n\t\t\t按任意键返回...");
getchar();
getchar();
break;
}
}
if(i==MAX_VERTEX_NUM)
{
printf("\n\n\t\t\t没有找到!");
printf("\n\n\t\t\t按任意键返回...");
getchar();
getchar();
}
break;
}
}while(c!='0');
}
void Menu()
{
printf("\n 学校导游图\n");
printf(" ┏━━━━━━━━━━━━━━━━━━━━┓\n");
printf(" ┃ 1.浏览校园全景 ┃\n");
printf(" ┃ 2.查询图中任意两个景点间的最短路径 ┃\n");
printf(" ┃ 3.查询图中任意两个景点间的所有路径 ┃\n");
printf(" ┃ 4.查看景点信息 ┃\n");
printf(" ┃ 5.退出系统 ┃\n");
printf(" ┗━━━━━━━━━━━━━━━━━━━━┛\n");
printf("请选择:");
}
void Browser(MGraph *G)
{
int i;
printf("┏━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓\n");
printf("┃编号┃景点名称 ┃简介 ┃\n");
for(i=1;i<=G->vexnum;i++)
printf("┃%-4d┃%-16s┃%-56s┃\n",G->vexs[i].num,G->vexs[i].name,G->vexs[i].introduction);
printf("┗━━┻━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛\n");
}
void main(void)
{
int i;
int v0,v1;
G=(MGraph *)malloc(sizeof(MGraph));
G=CreatUDN(G);
Menu();
scanf("%d",&i);
while(i!=5)
{
switch(i)
{
case 1:system("cls");Browser(G);Menu();break;
case 2:system("cls");
printf("\n\n\t\t\t请选择起点景点:");
scanf("%d",&v0);
printf("\t\t\t请选择终点景点:");
scanf("%d",&v1);
ShortestPath_DIJ(G,v0); /* 计算两个景点之间的最短路径 */
output(v0,v1); /* 输出结果 */
Menu();break;
case 3:system("cls");
// Floyd(G);
SearchAllpath(G);
Menu();break;
case 4:system("cls");search(G);Menu();break;
case 5:exit(1);break;
default:break;
}
scanf("%d",&i);
}
}
转载于:https://my.oschina.net/Cw6PKk/blog/832041