1、任务内容
城市公共交通站点,站点之间的道路,及道路长度实际构成数学意义上的无向加权图。现请设计实现一个算法,求任意两站点间最短路径距离且输出该最短路径上的每个站点,然后给一个乘车换乘方案。
2、需求分析
(1)显示站点信息:输入某个站点,程序显示停靠该站点的公交线路。
(2)显示公交信息:输入某个公交线路,程序显示该线路所经过的站点。
(3)查询出行方案:输入起始站和终点站,程序给出最短的路线,同时给出公交乘车及换乘的方案。
3、程序设计
(1)数据结构:
struct Point //站点
{
int no; //公交站点编号
char board[5]; // 站牌:该站有哪几路公交车经过
};
struct MatGraph //图的邻接矩阵类型
{
int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数、边数
Point poi[MAXV]; //站点信息
};
创建一个无向不带权图。其中,用邻接矩阵来存储站点样图中的路径信息;每个站点用一个数组来记录有哪几路公交车经过,若公交1路经过站点1,则poi[0].board[0]=1,若不经过则为0。
(2)功能实现:
①显示站点信息:
输入某个站点,程序遍历该站点的board数组,若board[i]=1,则说明公交线路i-1停靠该站点,将该线路输出。
②显示公交信息:
程序遍历该公交线路n的poi数组,若poi[i].board[n-1]=1,则说明公交线路i-1停靠该站点,将该站点输出。
③查询出行方案:
无向图存储完毕后,调用Floyd算法,用两个矩阵D[][]、P[][]记录每两个站点间的最短路径和中转点。输入起始站a和终点站b,记录当前站点now为起始站存储位a-1,记录下一站next为a到b的第一个中转点P[a-1][b-1]。比较now和next站点的board数组,如果这两个站点的board[i]都为1,即两个站点有相同公交线路,则乘坐该线路向前。记录下当前乘坐的线路j。之后进入循环,更新当前站now为next,更新下一站next为新的中转点即P[now][b-1]。继续比较两个站点是否有相同线路。比较中,如果当前乘坐的线路与之前记录的线路j不同,则视为换乘。继续该循环直到下一站next为终点站存储位b-1,出行方案显示完成。
4、遗留及待优化问题
(1)邻接矩阵存储线路信息,图的边数少,浪费大量内存空间,若使用邻接表形式则会更加节省空间。
(2)使用普通数组存储公交车信息,浪费内存空间。可使用bfs或dfs等算法降低空间开销。
(3)无法做到查询最少换乘方案的功能。
完整代码
//2019-2020学年第二学期 算法设计与应用实训
#include
#include
#include
#define INF 9999
#define MAXV 25
using namespace std;
struct Point //站点
{
int no; //公交站点编号
int board[5]; // 站牌:该站有哪几路公交车经过
};
struct MatGraph //图的邻接矩阵类型
{
int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数、边数
Point poi[MAXV]; //站点信息
};
void CreateMat(MatGraph &g) //图的创建
{
int i,j;
int A[MAXV][MAXV]= //邻接矩阵
{
{0,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{1,0,1,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,1,0,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,1,0,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,1,INF,INF,0,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,1,INF,0,INF,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,1,INF,0,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,1,0,1,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,1,INF,1,0,1,INF,1,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,1,0,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,1,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,INF,0,INF,INF,1,1,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,INF,1,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,INF,1,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,INF,0,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,0,1,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,1,0,INF,INF,1,1,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,INF,0,1,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,0,INF,INF,INF,1},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,0,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,INF,0,1,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,0,1},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,1,INF,INF,1,0}
};
g.n=MAXV;g.e=26; //边和点的数量
for(i=0;i<g.n;i++)
{
g.poi[i].no=i+1; //站点编号赋值
for(j=0;j<5;j++)
g.poi[i].board[j]=0; //站牌初始化为空
for(j=0;j<g.n;j++)
g.edges[i][j]=A[i][j];
}
g.poi[0].board[0]=1; //站牌:该站点有某路公交车经过
g.poi[1].board[0]=1;g.poi[1].board[1]=1;
g.poi[2].board[0]=1;
g.poi[3].board[0]=1;
g.poi[4].board[1]=1;
g.poi[5].board[0]=1;
g.poi[6].board[1]=1;
g.poi[7].board[0]=1;g.poi[7].board[1]=1;
g.poi[8].board[0]=1;g.poi[8].board[1]=1;g.poi[8].board[2]=1;
g.poi[9].board[2]=1;
g.poi[10].board[0]=1;
g.poi[11].board[2]=1;
g.poi[12].board[1]=1;g.poi[12].board[4]=1;
g.poi[13].board[0]=1;
g.poi[14].board[2]=1;
g.poi[15].board[4]=1;
g.poi[16].board[1]=1;
g.poi[17].board[3]=1;
g.poi[18].board[2]=1;g.poi[18].board[3]=1;
g.poi[19].board[4]=1;
g.poi[20].board[4]=1;
g.poi[21].board[2]=1;
g.poi[22].board[3]=1;
g.poi[23].board[3]=1;
g.poi[24].board[3]=1;g.poi[24].board[4]=1;
}
void main1(MatGraph g) //显示站点信息
{
int number;
cout<<"请输入想要显示的站点序号(1-25):";
cin>>number;
cout<<"站点"<<number<<"经过的公交线路为:";
for(int i=0;i<5;i++)
if(g.poi[number-1].board[i]==1) cout<<"公交"<<i+1<<"路 ";
cout<<endl;
}
void main2(MatGraph g) //显示公交信息
{
int number;
cout<<"请输入想要显示的公交线路(1-5):";
cin>>number;
cout<<"公交"<<number<<"路途经的站点有:";
for(int i=0;i<MAXV;i++)
{
if(g.poi[i].board[number-1]==1)
cout<<"站点"<<i+1<<" ";
}
cout<<endl;
}
void Floyd(MatGraph g,int D[MAXV][MAXV],int P[MAXV][MAXV]) //Floyd算法
{
int i,j,k;
for(i=0;i<g.n;i++)
for(j=0;j<g.n;j++)
{
D[i][j]=g.edges[i][j]; //记录最短路径
P[i][j]=j; //记录最短路径的第一个中转点
}
for(i=0;i<g.n;i++) //i为新增中转点
for(j=0;j<g.n;j++)
for(k=0;k<g.n;k++)
if(D[j][k]>(D[j][i]+D[i][k])) //如果经过i中转点,j到k的路径变短
{
D[j][k]=(D[j][i]+D[i][k]); //更新j到k的最短路径
P[j][k]=P[j][i]; //更新该路径的第一个中转点为i
}
}
void main3(MatGraph g,int D[MAXV][MAXV],int P[MAXV][MAXV]) //查询出行方案
{
int a,b,i,j;
cout<<"请输入起始站(1-25):";
cin>>a;
cout<<"请输入终点站(1-25):";
cin>>b;
cout<<"站点"<<a<<"到站点"<<b<<"的最短出行方案为:";
int now=a-1; //当前站为a
int next=P[a-1][b-1]; //下一站为a到b的第一个中转点
cout<<"站点"<<a;
for(i=0;i<5;i++)
if(g.poi[now].board[i]==1&&g.poi[next].board[i]==1) //如果当前站和下一站的站牌都有某一公交线路,即两站间有某公交连通
{
cout<<"(乘坐公交"<<i+1<<"路)" ;
j=i; //记录下当前乘坐的公交
break;
}
while(next!=b-1) //直到下一站为终点站,循环结束
{
cout<<"-->站点"<<next+1;
now=next; //当前站更新
next=P[now][b-1]; //下一站更新为本站到终点站的第一个中转点
for(i=0;i<5;i++)
if(g.poi[now].board[i]==1&&g.poi[next].board[i]==1) //继续寻找连通两站的公交
{
if(i!=j) //如果该公交i与之前乘坐的公交j不同,则换乘
{
cout<<"(换乘公交"<<i+1<<"路)" ;
j=i;
}
break;
}
}
cout<<"-->站点"<<b<<endl;
}
int main()
{
MatGraph map;
CreateMat(map);
int D[MAXV][MAXV],P[MAXV][MAXV];
Floyd(map,D,P);
int choose;
while(1)
{
cout<<" "<<endl;
cout<<" ---------------------------------------- "<<endl;
cout<<" | 通讯录 |"<<endl;
cout<<" | |"<<endl;
cout<<" | 1.显示站点信息 |"<<endl;
cout<<" | |"<<endl;
cout<<" | 2.显示公交信息 |"<<endl;
cout<<" | |"<<endl;
cout<<" | 3.查询出行方案 |"<<endl;
cout<<" | |"<<endl;
cout<<" | 0.退出 |"<<endl;
cout<<" | |"<<endl;
cout<<" ---------------------------------------- "<<endl;
cout<<"请选择:";
leap0:
cin>>choose;
if(choose<0||choose>3)
{
cout<<"请输入0-3的数字:";
goto leap0;
}
else
switch(choose)
{
case 1:main1(map);break;
case 2:main2(map);break;
case 3:main3(map,D,P);break;
case 0:exit(0);
default:cout<<"输入有误,请重新输入:"<<endl;goto leap0;
}
}
return 0;
}
仅作留档。