Floyd算法(任意两点间的最短路径)

Floyd(弗洛伊德)算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd算法的时间复杂度为O(N3),空间复杂度为O(N2)。

算法思想:

     Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)

      从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

算法步骤:

a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。   

b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。

给出矩阵,其中矩阵A是邻接矩阵,而矩阵Path记录u,v两点之间最短路径所必须经过的点

用处:可以通过以每个顶点作为源点循环求出每对顶点之间的最短路径,也可以用于求两顶点之间最短路径。

通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。

从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出矩阵D(n)。矩阵D(n)ij列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的距离矩阵。

其状态转移方程如下: D(k)[i,j]:=min{D(k-1)[i,k]+D(k-1) [k,j], D(k-1)[i,j]}

优化后map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}

map[i,j]表示ij的最短距离是穷举i,j的断点,map[n,n]初值应该为0,或者按照题目意思来做。

#include <stdio.h>
#define MAXV 100
#define INF 9999
typedef struct{
int edges[MAXV][MAXV];
int n,e;
}MGraph;
void ppath(int path[][MAXV],int i,int j)
{
	int k;
	k=path[i][j];
	if (k==-1)  return;
	ppath(path,i,k);
	printf("%d,",k);
	ppath(path,k,j);
}
void DisPath(int A[][MAXV],int path[][MAXV],int n)
{
	int i,j;
	for (i=0;i<n;i++)
		for (j=0;j<n;j++)
			if (A[i][j]!=INF && i!=j)
			{
				printf("  从%d到%d路径为:",i,j);
				printf("%d,",i);
				ppath(path,i,j);
				printf("%d",j);
				printf("\t路径长度为:%d\n",A[i][j]);
			}
}
void Floyd(MGraph g)	//弗洛伊德算法从每对顶点之间的最短路径
{
	int A[MAXV][MAXV],path[MAXV][MAXV];
	int i,j,k,n=g.n;
	for (i=0;i<n;i++)						//给A数组置初值
		for (j=0;j<n;j++)
		{
			A[i][j]=g.edges[i][j];
			path[i][j]=-1;
		}
	for (k=0;k<n;k++)						//计算Ak
	{
	for (i=0;i<n;i++)
		for (j=0;j<n;j++)
			if (A[i][j]>(A[i][k]+A[k][j]))
				{	A[i][j]=A[i][k]+A[k][j];
					path[i][j]=k;
				}
	}
	printf("\n输出最短路径:\n");
	DisPath(A,path,n);			//输出最短路径
}
void DispMat(MGraph g)
//输出邻接矩阵g
{
	int i,j;
	for (i=0;i<g.n;i++)
	{
		for (j=0;j<g.n;j++)
			if (g.edges[i][j]==INF)
				printf("%3s","∞");
			else
				printf("%3d",g.edges[i][j]);
		printf("\n");
	}
}
int main()
{
	int i,j;
	MGraph g;
	int B[MAXV][6]={
		{0,5,INF,7,INF,INF},
		{INF,0,4,INF,INF,INF},
		{8,INF,0,INF,INF,9},
		{INF,INF,5,0,INF,6},
		{INF,INF,INF,5,0,INF},
		{3,INF,INF,INF,1,0}};
	g.n=6;g.e=10;
	for(i=0;i<g.n;i++)
		for (j=0;j<g.n;j++)
			g.edges[i][j]=B[i][j];
			DispMat(g);
Floyd(g);
	printf("\n");
	return 0;
}


还是以上次的图为例



参考博客:最短路径—Dijkstra算法和Floyd算法 

对于两种算法的思想讲的比较详细,不懂得可以看一下。

https://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html

#include <stdio.h>
#define MAXV 100
#define INF 99999
int A[MAXV][MAXV],path[MAXV][MAXV];
typedef struct
{
    int edges[MAXV][MAXV];
    int n,e;
} Mg;
void ppath(int i,int j)
{
    int k;
    k=path[i][j];
    if (k==-1)
        return;
    ppath(i,k);
    printf("%d,",k);
    ppath(k,j);
}
void DisPath(int n)
{
    int i,j;
    for (i=0; i<n; i++)
        for (j=0; j<n; j++)
            if(A[i][j]!=INF&&i!=j)
            {
                printf("从%d到%d路径为:",i,j);
                printf("%d,",i);
                ppath(i,j);
                printf("%d",j);
                printf("\t路径长度为:%d\n",A[i][j]);
            }
}
void floyd(Mg g)
{
    int i,j,k,n=g.n;
    for (i=0; i<n; i++)
        for (j=0; j<n; j++)
        {
            if(g.edges[i][j])
            {
            A[i][j]=g.edges[i][j];
            path[i][j]=-1;
            }
        }
    for (k=0; k<n; k++)
    {
        for (i=0; i<n; i++)
            for (j=0; j<n; j++)
                if (A[i][k]!=INF&&A[k][j]!=INF&&A[i][j]>(A[i][k]+A[k][j]))//注意判断条件
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=k;
                }
    }
    for(i=0;i<n;i++)
       {
for(j=0;j<n;j++)
    {
        printf("%d ",A[i][j]);
    }
    printf("\n");
       }
    printf("\n输出最短路径:\n");
    DisPath(n);
}
int main()
{
    Mg g;
    scanf("%d %d",&g.n,&g.e);
    int i,j;
    for(i=0; i<g.n; i++)
        for(j=0; j<g.n; j++)
        {
            if(i==j)
                A[i][j]=0;
            else
                A[i][j]=INF;
        }
    for(i=g.e; i>0; i--)
    {
        int v1,v2,Q;
        scanf("%d %d %d",&v1,&v2,&Q);
        g.edges[v1][v2]=Q;
    }
    floyd(g);
    return 0;
}


  • 26
    点赞
  • 146
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黎曼猜想·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值