(1)问题描述
设计一个校园导游程序,为来访的客人提供各种信息查询服务。
(2)设计要求
- 设计中北大学的校园平面图。以图中顶点表示校内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
- 为来访客人提供图中任意景点相关信息的查询。
- 为来访客人提供图中任意景点的问路查询,即查询任意两相景点之间的一条最短的简单路径。
- 求校园图的关节点。
- 为来访客人提供图中任意景点问路查询,即求任意两个景点之间的所有路径。
- 为来访客人提供校园图中多个景点的最佳访问路线查询,即求途经这多个景点的最佳路径。
(3)代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define INF 0x3f3f3f3f//无穷大
#define MAX 20//顶点最大值
typedef struct//顶点类型
{
char name[20];
int ID;
char info[500];
} vertextype;
typedef int edgetype;//边权值类型
typedef struct
{
vertextype vexs[MAX];
edgetype edges[MAX][MAX];//邻接矩阵图类型
int n, e;
} graph;
typedef int dist[MAX][MAX]; /* 距离向量类型*/
typedef int path[MAX][MAX]; /* 路径类型*/
graph g;
void plan()
{
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");
printf("┃ │德怀楼⒀│ ┃\n");
printf("┃ ╰────╯ ┃\n");
printf("┃ ║ ┃\n");
printf("┃ ╭───╮ ┃\n");
printf("┃ │正门⒁│ ┃\n");
printf("┃ ╰───╯ ┃\n");
printf("┃ ┃\n");
printf("┃ 注:括号中数字代表景点序号 ┃\n");
printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
}
void mean()
{
printf("\t\t\t\t┏━━━━━━━━━━━━━━━━━━━┓\n");
printf("\t\t\t\t┃ **请选择功能** ┃\n");
printf("\t\t\t\t┃ 1.查询景点信息 ┃\n");
printf("\t\t\t\t┃ 2.查询推荐路线 ┃\n");
printf("\t\t\t\t┃ 3.查询校园图关节点 ┃\n");
printf("\t\t\t\t┃ 4.退出 ┃\n");
printf("\t\t\t\t┗━━━━━━━━━━━━━━━━━━━┛\n");
}
void sub_mean()
{
printf("\t\t\t\t┏━━━━━━━━━━━━━━━━━━━┓\n");
printf("\t\t\t\t┃ **请选择功能** ┃\n");
printf("\t\t\t\t┃ 1.查询两景点的最佳路径 ┃\n");
printf("\t\t\t\t┃ 2.查询两景点之间所有路径 ┃\n");
printf("\t\t\t\t┃ 3.查询途径多个景点的最佳访问路线 ┃\n");
printf("\t\t\t\t┃ 4.退出 ┃\n");
printf("\t\t\t\t┗━━━━━━━━━━━━━━━━━━━┛\n");
//*printf("请选择功能:");
}
/*函数功能:建立图的邻接矩阵存储结构*/
void creat_graph(char *s, int c)
{
int i, j, k, w;
FILE *rf;
rf = fopen(s, "r");
if (rf)
{
fscanf(rf, "%d%d", &g.n, &g.e);
for (i = 1; i<=g.n; i++)
{
fscanf(rf, "%d%s ", &g.vexs[i].ID, g.vexs[i].name);
fgets(g.vexs[i].info, 500, rf);
}
for (i = 1; i<=g.n; i++)
for (j = 1; j<=g.n; j++)
if (i == j) g.edges[i][j] = 0;
else g.edges[i][j] = INF;
for (k = 0; k<g.e; k++)
{
fscanf(rf, "%d%d%d", &i, &j, &w);
g.edges[i][j] = w;
if (c == 0) g.edges[j][i] = w; /*如果c==0则建立无向图邻接矩阵,否则建立有向图邻矩阵*/
}
fclose(rf);
}
else g.n = 0;
}
/*函数功能:Floyd方法求所有顶点对间的最短路径*/
void floyd(path p, dist d)
{
int i, j, k;
for (i = 1; i<=g.n; i++)
for (j = 1; j<=g.n; j++)
{
d[i][j] = g.edges[i][j];
p[i][j]=j;
}
for (k = 1; k<=g.n; k++) /*递推求解每一对顶点间的最短距离*/
{
for (i = 1; i<=g.n; i++)
for (j = 1; j<=g.n; j++)
if (d[i][j]>(d[i][k] + d[k][j]))
{
d[i][j] = d[i][k] + d[k][j];
p[i][j] = p[i][k];
}
}
}
/*函数功能输出最短路径*/
void put_short(int sta, int end,path p, dist d)
{
printf("\n最短距离为:\n");
printf("%dM", d[sta][end]);
printf("\n最佳路线为:\n");
int tmp=sta;
printf("(%d)%s",sta,g.vexs[sta].name);
while(tmp!=end)
{
tmp=p[tmp][end];
printf(" -> (%d)%s",tmp,g.vexs[tmp].name);
}
printf("\n");
}
int min(int a,int b)
{
return a>b?b:a;
}
/*函数功能:求割点的dfs过程*/
void cut_dfs(int u,int *vis,int *dfn,int *par,int*low,int *cut)
{
int v;
static int dep=0;
int child=0;
vis[u]=1;
dfn[u]=low[u]=++dep;
for(v=1; v<=g.n; v++)
{
if(g.edges[u][v]!=INF&&g.edges[u][v])
{
if(!vis[v])
{
child++;
par[v]=u;
cut_dfs(v,vis,dfn,par,low,cut);
low[u]=min(low[u],low[v]);
if(par[u]==-1&&child>1)
{
cut[u]=1;
}
else if(par[u]!=-1&&low[v]>=dfn[u])
{
cut[u]=1;
}
}
else if(v!=par[u])
{
low[u]=min(low[u],dfn[v]);
}
}
}
}
/*函数功能:求割点*/
void cutver()
{
int vis[MAX],dfn[MAX],par[MAX],low[MAX],cut[MAX];
int i;
int flag=0;
for(i=1; i<=g.n; i++)
{
vis[i]=0;
par[i]=-1;
cut[i]=0;
}
for(i=1; i<=g.n; i++)
{
if(!vis[i])
{
cut_dfs(i,vis,dfn,par,low,cut);
break;
}
}
for(i=1; i<=g.n; i++)
if(cut[i])
{
flag=1;
break;
}
if(flag)
{
printf("校园图的关节点为:");
for(i=1; i<=g.n; i++)
{
if(cut[i])
{
flag=1;
printf(" (%d)%s",i,g.vexs[i].name);
}
}
printf("\n");
}
else
{
printf("对不起,该校园图没有关节点!\n");
}
}
/*函数功能:求两点间所有路径过程中求遍历过中的下一个点*/
int find_first(int cur,int vis_ver[],int vis_edg[][MAX])
{
int i;
for(i=1; i<=g.n; i++)
if(!vis_ver[i]&&!vis_edg[cur][i]&&g.edges[cur][i]!=INF&&i!=cur)
return i;
return -1;
}
/*函数功能:求两点间的所有路径*/
void all_path(int sta,int end)
{
int i;
int vis_ver[MAX],vis_edg[MAX][MAX];
int stack[MAX],top=-1;
memset(vis_ver,0,sizeof(vis_ver));
memset(vis_edg,0,sizeof(vis_edg));
vis_ver[sta]=1;
stack[++top]=sta;
while(top>=0)
{
int em=stack[top];
if(em==end)
{
for(i=0; i<top; i++)
printf("(%d)%s -> ",stack[i],g.vexs[stack[i]].name);
printf("(%d)%s\n",stack[top],g.vexs[stack[top]].name);
printf("\n");
vis_ver[em]=0;
top--;
}
else
{
int cur=find_first(em,vis_ver,vis_edg);
if(cur>=0)
{
stack[++top]=cur;
vis_ver[cur]=1;
vis_edg[em][cur]=1;
}
else if(cur==-1)
{
vis_ver[em]=0;
for(i=1; i<=g.n; i++)
vis_edg[em][i]=0;
top--;
}
}
}
}
/*函数功能:求途径多个点的最佳路径的辅助输出函数*/
void shiftput(int sta, int end,path p, dist d)
{
int tmp=sta;
while(tmp!=end)
{
tmp=p[tmp][end];
printf(" -> (%d)%s",tmp,g.vexs[tmp].name);
}
}
/*函数功能:求途径多个点的最佳路径*/
void road_path(int staver,int *path_ver,int vercou,path p,dist d)
{
int i,vis[MAX];
memset(vis,0,sizeof(vis));
for(i=0; i<vercou; i++)
vis[path_ver[i]]=2;//表示要经过的点
vis[staver]=1;
int cur=staver;
int flag=1;
printf("(%d)%s",staver,g.vexs[staver].name);
while(1)
{
flag=0;
int mindis=INF,minver=-1;
for(i=1; i<=g.n; i++)
{
if(vis[i]==2)
{
flag=1;
if(d[cur][i]<mindis)
{
mindis=d[cur][i];
minver=i;
}
}
}
if(flag==0) break;
shiftput(cur,minver,p,d);
vis[minver]=1;
cur=minver;
}
printf("\n");
}
int main()
{
creat_graph("graph.txt", 0);
plan();
mean();
int cho,sub_cho;
while(scanf("%d",&cho))
{
getchar();
int i;
int staver, endver;
int vernum,vercou;
char yorn;
dist d;
path p;
int path_ver[MAX];
switch(cho)
{
case 1:
yorn='y';
while(1)
{
if(yorn=='n')
{
system("cls");
plan();
mean();
break;
}
else if(yorn=='y')
{
system("cls");
plan();
printf("请输入景点序号:");
scanf("%d", &vernum);
getchar();
puts(g.vexs[vernum].info);
}
else
{
printf("输入错误!\n");
}
printf("是否继续查询景点信息?y/n ");
scanf("%c",&yorn);
getchar();
}
break;
case 2:
yorn='y';
while(1)
{
if(yorn=='n')
{
out:system("cls");
plan();
mean();
break;
}
else if(yorn=='y')
{
system("cls");
plan();
sub_mean();
scanf("%d",&sub_cho);
getchar();
switch(sub_cho)
{
case 1:
floyd(p,d);
yorn='y';
while(1)
{
if(yorn=='n')
{
system("cls");
plan();
sub_mean();
break;
}
else if(yorn=='y')
{
system("cls");
plan();
printf("请输入起点序号:");
scanf("%d",&staver);
getchar();
printf("请输入终点序号:");
scanf("%d",&endver);
getchar();
put_short(staver,endver,p,d);
}
else
{
printf("输入错误!");
}
printf("是否继续查询两点之间最短路径?y/n ");
scanf("%c",&yorn);
getchar();
}
break;
case 2:
yorn='y';
while(1)
{
if(yorn=='n')
{
system("cls");
plan();
sub_mean();
break;
}
else if(yorn=='y')
{
system("cls");
plan();
printf("请输入起点序号:");
scanf("%d",&staver);
getchar();
printf("请输入终点序号:");
scanf("%d",&endver);
getchar();
all_path(staver,endver);
}
else
{
printf("输入错误!");
}
printf("是否继续查询两点之间所有路径?y/n ");
scanf("%c",&yorn);
getchar();
}
break;
case 3:
floyd(p,d);
yorn='y';
while(1)
{
if(yorn=='n')
{
system("cls");
plan();
sub_mean();
break;
}
else if(yorn=='y')
{
system("cls");
plan();
printf("请输入起点序号:");
scanf("%d",&staver);
getchar();
printf("请输入要经过的景点数目:");
scanf("%d",&vercou);
getchar();
printf("依次输入要经过的景点序号:\n");
for(i=0; i<vercou; i++)
{
scanf("%d",&path_ver[i]);
getchar();
}
road_path(staver,path_ver,vercou,p,d);
}
else
{
printf("输入错误!");
}
printf("是否继续查询途径多个景点的最佳路径?y/n ");
scanf("%c",&yorn);
getchar();
}
break;
case 4:
goto out;
break;
default:
printf("输入错误!");
}
}
printf("是否继续查询推荐路线?y/n ");
scanf("%c",&yorn);
getchar();
}
break;
case 3:
cutver();
printf("按任意键返回主菜单...");
getchar();
system("cls");
plan();
mean();
break;
case 4:
return 0;
default:
printf("输入错误!");
}
}
return 0;
}