最短路径(弗洛伊德算法 迪杰斯特拉算法 贝尔曼-福特算法)
弗洛伊德算法:
弗洛伊德算法核心代码:
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
上述代码只有五行,时间复杂度是N的三次方。本算法最大的优点就是代码简洁。在对时间复杂度要求不高的情况下,可以通过此算法找到任意两点间或者指定一点到另一点的最小距离。
思路:
寻找两点间的最小距离,我们可以通过引入中间点来寻找最短距离。例如:我们需要寻找i和j两点间的最小距离,那么我们可以引入中间点k,通过判断i到k再到j的距离是否小于此时i到j的距离,如果是,则更新i到j点的距离。此算法运用了动态规划的思想。
具体代码如下:
#include <stdio.h>
int dis[105][105],n,q,a,b,c,Inf=1e9;
int min(int x,int y)
{
return x<y?x:y;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j)
dis[i][j]=Inf;
}
}
for(int i=0;i<q;i++)
{
scanf("%d%d%d",&a,&b,&c);
dis[a][b]=min(dis[a][b],c);
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//防止重边
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d ",dis[i][j]);
}
printf("\n");
}
return 0;
}
贝尔曼-福特算法
核心代码:
for(int i=0;i<n-1;i++)
{
for(int j=0;j<m;j++)
{
dis[v[j]]=min(dis[v[j]],dis[u[j]]+w[j]);
}
}
贝尔曼-福特算法用来寻找指定点到其他点的最短距离,并且可以解决迪杰斯特拉算法不能解决的负权值问题。缺点是时间复杂度较高。
上述代码表明,我们有m条边。而我们的目的就是通过选择不同的边来寻找两点间的最短距离。外循环一共循环了n-1次,表示两点间最多有n-1条边。内循环枚举每一条边,通过比较来寻找最多通过i+1条边时,两点间的最短距离。而我们发现,很多情况下,不必循环n-1次,某些点便已经找到了最短距离,此后用这些点去更新所连接的点,不会产生任何影响。这就启发我们,**每次只处理最短路数值发生变化的点,因为只有发生变化的点,与其有临边的点的最短路才有可能变化。**所以我们采用队列优化的方式,来实现贝尔曼-福特算法。
代码如下:
#include <stdio.h>
int n,m,dis[1005],u[1005],w[1005],v[1005],first[1005],next[1005],head,tail,que[10000],temp,b[1005]; //为了减少复杂度,我们采用邻接表储存图
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
next[i]=-1;
first[i]=-1;
dis[i]=1e9;
}
dis[1]=0;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]]; //next[i]储存的是以i号路的上一条路的编号
first[u[i]]=i; //first[u[i]]储存的是以u[i]为顶点的第一条路的编号
}
head=0;
tail=1;
que[head]=1;
temp=first[que[head]];
while(tail>head)
{
while(temp!=-1)
{
if(dis[v[temp]]>dis[u[temp]]+w[temp])
{
if(!b[v[temp]])
{
b[v[temp]]=1;
que[tail++]=v[temp];
}
dis[v[temp]]=dis[u[temp]]+w[temp];
}
temp=next[temp];
}
book[que[head]]=0;
head++;
}
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
return 0;
}