以下为各种最短路算法
Floyd
时间复杂度:O(n^3)
适用范围:求任意两点间的最短路,能够处理负边权,但无法处理负权回路。
主要思想:利用DP的思想,dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]),不断更新至最优。
中心代码:
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (dis[i][j]>dis[i][k]+dis[k][j]&&i!=k&&k!=j&&j!=i)
dis[i][j]=dis[i][k]+dis[k][j];
Dijkstra
时间复杂度:O(n^2)
适用范围:单源最短路径(稳定性最高的算法),无法处理负边权。
主要思想:将图所有点的集合 S 分为两部分,V 和 S-V。V 集合是已经得到最短路径的点的集合,在初始情况下 V 中只有一个顶点 t,S-V 是还未得到最短路径点的集合。然后,在每一次迭代过程中取得 S-V 集中到 V 集合任一点距离最短的点,将其加到 V 集合,从 S-V 集合删除。重复此过程直到 S-V 集合为空。(非本人所写)
中心代码(邻接矩阵存图):
for (int i=1;i<=n;i++){
ans=0x7fffffff;
for (int j=1;j<=n;j++)
if ((f[j])&&(dist[j]<ans)) {
ans=dist[j];
st=j;
}
f[st]=false;
for (int j=1;j<=n;j++)
if ((f[j])&&(dist[j]>dist[st]+g[st][j]))
dist[j]=dist[st]+g[st][j];
}
练手题见SPFA
Bellman—Ford
时间复杂度:O(nm)
适用范围:单源最短路径,能够处理负边权,能够判断是否有负权回路。
主要思想:从起点出发,每次枚举已做过的点连接的所有边,修改未做过的点的距离,直到所有点都被更新。
中心代码:
for (int i=1;i<n;i++)
for (int j=1;j<=m;j++)
if (dis[u]+w[j]<dis[v])
dis[v]=dis[u]+w[j];
练手题见SPFA
SPFA
时间复杂度:O(km)(k为常数,平均值为2)
适用范围:同Bellman—Ford。
主要思想:同Bellman—Ford,用队列优化每次修改操作(其实叫做松弛操作)
中心代码:
while(head<tail){
int x=que[++head];
exist[x]=false;
for (int i=h[x];i;i=ed[i].next){
dis[ed[i].to]=min(dis[ed[i].to],dis[x]+ed[i].dis);
if (!exist[ed[i].to]){
que[++tail]=ed[i].to;
exist[ed[i].to]=true;
}
}
}
练手题:HDUP2544、HDUP1874、HDUP2066(第一题和第三题题解博主有哦!第一题题解 第三题题解)
就这样吧,有误还请多多指正!