#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; }