基于vector的邻接表解决最短路稀疏图的问题

来源:互联网 发布:编程pmc 编辑:程序博客网 时间:2024/05/22 00:08
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?


Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 11 2 33 31 2 52 3 53 1 20 0
Sample Output
32


裸的最短问题,dijkstra和Floyd都可以做,这里N 的范围比较小,但是如果N非常大但是M很小的话,dijkstra的邻接矩阵存储图会爆内存,下面用邻接表来实现存图

这里用vector来实现邻接表的操作


#include<iostream>#include<vector>#include<algorithm>#include<cstring>#include<string>#include<cstdio>#include<cstdlib>#define N 110#define INF 0x3f3f3f3fusing namespace std;int n,m,a,b,c,vis[N],dis[N],Min;struct node{    int d,w;};//定义一个结构体来存储每个入度点以及对应边的权值//比如边u->v,权值为w,node结构体存储的就是v以及w。vector<node>v[N];void dijkstra();int main(){    //对于N非常大但是M很小的这种稀疏图来说,用邻接矩阵N*N是存不下的。邻接矩阵是将所有的点都存储下来了,然而    //对于稀疏图来说,有很多点是没有用到的,把这些点也存储下来的话就会很浪费空间。可以用邻接表来存储,这里借助vector来实现邻接表的操作。    //用邻接表存储时候,只存储有用的点,对于没有用的点不存储,实现空间的优化。    while(cin>>n>>m,n!=0||m!=0)    {        for(int i=0; i<=n; i++)            v[i].clear();//将vecort数组清空        for(int i=1; i<=m; i++) //用vector存储邻接表        {            node nd;            scanf("%d%d%d",&a,&b,&c);            nd.d=b,nd.w=c;//将入度的点和权值赋值给结构体            v[a].push_back(nd);//将每一个从a出发能直接到达的点都压到下标为a的vector数组中,以后遍历从a能到达的点就可以直接遍历v[a]            nd.d=a,nd.w=c;//无向图的双向存边            v[b].push_back(nd);        }        dijkstra();        printf("%d\n",dis[n]);    }    return 0;}void dijkstra(){    //初始位置从顶点1开始。    memset(vis,0,sizeof(vis));//初始化标记数组    for(int i=0; i<=n; i++)        dis[i]=INF;//先将dis初始化为无穷大,下面更新dis的初始值。    int len=v[1].size();//找到从起始位置能到达的点有几个,v[1]的大小就是能到达的点的个数    for(int i=0; i<len; i++) //循环遍历每个点然后更新dis初始值    {        if(dis[v[1][i].d]>v[1][i].w)//v[1][i].d代表从1出发能到达的顶点中第i个点的值,            //dis数组记录从1出发到该顶点的距离,v[1][i].w代表从1出发能到达的顶点中,到达第i个顶点的边的权值            dis[v[1][i].d]=v[1][i].w;//更新dis数组,这里更新的时候包括了对重边的更新    }    vis[1]=1;    int k;    for(int i=1; i<n; i++)    {        Min=INF;        for(int j=1; j<=n; j++) //dijkstra找最近的点        {            if(vis[j]==0&&dis[j]<Min)            {                Min=dis[j];                k=j;            }        }        vis[k]=1;//k为找到的点        len=v[k].size();//从k出发能到达的点的个数        for(int j=0; j<len; j++) //循环遍历k能到达的点(假设为vi),比较从源点到达q的距离,和从源点出发借助k这个点中转再到达q的距离,然后更新dis数组        {            int vi=v[k][j].d;//v[k][j].d代表从k出发能到达的顶点中第j个顶点的值            if(vis[vi]==0&&dis[vi]>dis[k]+v[k][j].w)//借助k这个点能进行松弛操作的话,更新                dis[vi]=dis[k]+v[k][j].w;        }    }}