Floyd 求最短路

算法思想:https://www.bilibili.com/video/BV1Ut41197NX?t=715

一,比较

Dijkstra : 是一种解决单源最短路径的算法,即 固定的一个点 到 余下所有点的最短路径

当若 我们要求所有点之间的最短路径呢?

一个方法是:将 Dij 用 n 次,不过这个时间复杂度一下子就到 n的3次方

于是,Floyd 想出了 Floyd算法 

Floyd: 解决所有顶点间的最短路径

二,步骤

1,初始化

用 邻接矩阵 ,对角线全为 0

若存在 <vi,vj>, 则为其权值,否则为 无穷大

 2,试探

试着在所有路径中,加入中间顶点 Vx,

若路径变小,则改邻接矩阵的值;否则不变

3,循环

试探完所有顶点,算法结束

三,例题 (注意这里是有向图)

四,代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MIN(x,y) (((x)<(y))?(x):(y))
#define inf 0x3f3f3f3f
#define N 105
int a[N][N];
int n;
void show()
{
    puts("");
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            printf("%d ", a[i][j]);
        }puts("");
    }
}
int main(void)
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)   //1,初始化    用 邻接矩阵 ,对角线全为 0   若存在 <vi, vj>, 则为其权值,否则为 无穷大
    {
        for (int j = 1; j <= n; j++)
            a[i][j] = inf;
        a[i][i] = 0;
    }

    int m; scanf("%d", &m);     // 边数
    while (m--)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        a[x][y] = w;
    }

    for (int k = 1; k <= n; k++)  // 3,循环  试探完所有顶点,算法结束
    {
        for (int i = 1; i <= n; i++)     // 2,试探     试着在所有路径中,加入中间顶点 Vx , 若路径变小,则改邻接矩阵的值;否则不变
        {
            for (int j = 1; j <= n; j++)
            {
                a[i][j] = MIN(a[i][j], a[i][k] + a[k][j]);
            }
        }
    }
    show();
    
    system("pause");
    return 0;
}/*
3 5
1 2 4
2 1 6
1 3 11
3 1 3
2 3 2
 */
View Code

注意:这里没有存路径

这里的测试数据是上面那个例题。

五,记录路径的方法

用一个数组 p[ i ][ j ] 表示 i 到 j 的最短路径上,终点 j 的前一个的名称。

步骤:

① 初始化

        for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
			p[i][j] = i;
	}

② 赋值

        for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (a[i][k] + a[k][j] < a[i][j])
				{
					a[i][j] = a[i][k] + a[k][j];
					p[i][j] = p[k][j];
				}
			}
		}
	}

③ 打印

这个是重点思想,要讲一下。

假设我们要找A->B的最短路径,那么就依次查找,假设 p[a][b] 的值为 c,即 b 的前一点是 c.

那么接着查找 p[a][c],假设 p[a][c] 的值为 d,

那么接着查找 p[a][d],假设 p[a][d] 的值为 a,则查找结束,最短路径为 a->d->c->b。

void path(int s, int e)
{
	if (p[s][e] != s)
		path(s, p[s][e]);
	printf("%d->", p[s][e]);
}
printf("%d
", e);

  注意这里终点是没有打印出来的,需要单独处理。

④ 完整代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define MIN(x,y) (x<y?x:y)
#define inf 0x3f3f3f3f
#define N 111
int a[N][N];
int p[N][N];
int n, m;
void init()
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            a[i][j] = inf;
            p[i][j] = i;
        }
        a[i][i] = 0;
    }
}
void floyd()
{
    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                //a[i][j] = MIN(a[i][j], a[i][k] + a[k][j]);
                if (a[i][k] + a[k][j] < a[i][j])
                {
                    a[i][j] = a[i][k] + a[k][j];
                    p[i][j] = p[k][j];
                }
            }
        }
    }
}
void path(int s, int e)
{
    if (p[s][e] != s)
        path(s, p[s][e]);
    printf("%d->", p[s][e]);
}
void show()
{
    puts("");
    for (int i = 1; i <= n; i++)   // 打印 邻接矩阵
    {
        for (int j = 1; j <= n; j++)
        {
            printf("%d ", a[i][j]);
        }puts("");
    }

    for (int i = 1; i <= n; i++)  // 求路径
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j)
                continue;
            printf("%d 到 %d 的最短路径:", i, j);
            path(i, j); 
            printf("%d
", j);
        }
    }
}
int main(void)
{
    scanf("%d%d", &n, &m);
    init();
    while (m--)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        a[u][v] = w;
    }
    floyd();
    show();

    system("pause");
    return 0;
}
View Code

=========== ======== ========= ======= ====== ===== ==== === == =

If there's any kind of magic in the world, it must be the attempt of understanding someone or share something.

                                            —Before Sunrise

其实最让我们挣扎、绝望的不是困难,而是身边没有一个值得相信的朋友,能让我敞开心扉跟他分享!

原文地址:https://www.cnblogs.com/asdfknjhu/p/13060731.html