Dijkstra算法 详细解释
Dijkstra算法适用于边权值为正的情况,如果边权值为负数就才用另一种最短路算法Bellman-Ford算法。
该算法是指从单个源点到各个结点的最短路,该算法适用于有向图和无向图。
复杂度O(n^2)
伪代码:
////伪代码
清楚所有点的标号
全部d[i] = INF
然后将图信息权值复制到d中
循环n次{
在所有为标号的结点中,选出d值最小的结点x
给x标记
对于从x出发的所有边(x,y),更新d[y] = min{d[y],d[y]+w(x,y)}
}
故而得到的代码模板:
void dijkstra(int u)
{
memset(v,0,sizeof v);
memset(dis,INF,sizeof dis);
v[u] = 1;
for(int i = 1; i <= n; i++)
dis[i] = min(dis[i],Map[u][i]);
for(int i = 1; i <= n; i++)
{
int x,m = INF;
for(int y = 1; y <= n; y++)
if(!v[y] && dis[y] <= m)
m = dis[x = y];
v[x] = 1;
for(int y = 1; y <= n; y++)
dis[y] = min(dis[y],dis[x]+Map[x][y] );
}
}
数据样例:
5 6 1
1 2 5
1 3 8
2 3 1
2 4 3
4 5 7
2 5 2
下面模拟一下(来源 请进入):
我们以1为源点,来求所有点到一号点的最短路径。
先建立一个dis数组,dis[i]表示第i号点到源点(1号点)的估计值,你可能会问为什么是估计值,因为这个估计值会不断更新,更新到一定次数就变成答案了,这个我们一会再说。
然后我们在建立一个临界矩阵,叫做:map,map[i][j]=v表示从i到j这条边的权值是v。
dis初始值除了源点本身都是无穷大。源点本身都是0.
先从1号点开始。一号点,map[1][2]=5,一号点离2号点是5,比无穷大要小,所以dis[2]从无穷大变成了5。顺便,我们用minn记录距离1号点最短的点,留着以后会用。
dis[0,5,∞,∞,∞]。minn=2。
然后搜到3号点,map[1][3]=8,距离是8,比原来的dis[3]的∞小,于是dis[3]=8。但是8比dis[2]的5要大,所以minn不更新。
dis[0,5,8,∞,∞]
接着分别搜索4,5号点,发现map[1][4],map[1][5]都是∞,所以就不更新。
现在,dis数组所呈现的明显不是最终答案,因为我们才更新一遍,现在我们开始第二次更新,第二次更新以什么为开始呢?就是以上一次我们存下来的,minn,相当于把2当源点,求所有点到它的最短路,加上它到真正的源点(1号点)的距离,就是我们要求的最短路。
从2号点开始,搜索3号点,map[2][3]=1,原本dis[3]=8,发现dis[2]+map[2][3]=5+1=6 dis[0,5,6,∞,∞] minn=3. 然后搜索4号点,map[2][4]=3,原本dis[4]=∞,所以,dis[2]+map[2][4]=5+3=8 dis[0,5,6,8,∞] minn=3. 接着搜索5号点,map[2][5]=2,5+2=7,7<∞,dis[5]=7minn不变。 dis[0,5,6,8,7] 二号点搜完,因为minn是3,继续搜索3号点。 三号点还是按照二号点的方法搜索,发现没有可以更新的,然后搜索四号。 四号搜5号点,发现8+7>5+2,所以依然不更新,然后跳出循环。 现在的估计值就全部为确定值了: dis[0,5,6,8,7] 这就是每个点到源点一号点的距离,我们来看一下代码: 上述算法采用邻接矩阵来存储边的信息,此种方法的时间复杂度为O(n^2)。 在很多情况中,图中的边并没有那么多,mlog(n) 比 n^2 小的多。m 远小于 n^2的图称为稀疏图,而 m 相对较大的图为稠密图。 稀疏图适合使用vector数组来储存,还有一种表示方法便是——邻接表。 #include