zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    RabbitMQ WindowServer2008R2 安装配置
    wpf的低调自定义属性面板PropertyGrid
    复旦大学2020--2021学年第二学期高等代数II期末考试情况分析
    复旦大学2020--2021学年第二学期(20级)高等代数II期末考试第七大题解答
    复旦大学2020--2021学年第二学期(20级)高等代数II期末考试第八大题解答
    复旦高等代数II(20级)每周一题
    复旦大学高等代数课程介绍
    consul 下线服务 服务注销脚本
    consul 集群搭建
    Linux Limit相关内容设置大全(值得收藏)
  • 原文地址:https://www.cnblogs.com/asdfknjhu/p/13060731.html
Copyright © 2011-2022 走看看