[啊哈算法]Floyd-Warshall

北战南征 提交于 2020-01-16 06:45:59

问题描述

Input
第一行四个数为n,m,n表示顶点个数,m表示边的条数。
接下来m行,每一行有三个数t1、t2 和t3,表示顶点t1到顶点t2的路程是t3。请注意这些t1->t2是单向的。
Output
输出一个n*n的矩阵,第n行第n列表示定点n到n的距离。每一行两个数间由空格隔开Sample Input
5 8
1 2 2
2 3 3
3 4 4
4 5 5
5 3 3
3 1 4
2 5 7
1 5 10
Sample Output
0 2 5 9 9
7 0 3 7 7
4 6 0 4 9
12 14 8 0 5
7 9 3 7 0
More Info
输出结果每行的最后一个数字后不需要留空格哦~

算法思想

当任意两点之间不允许经过第三个点时,这些城市之间最短路程就是初始路程。
假如现在只允许经过1号顶点,求任意两点之间的最短路程,应该如何求呢?只需判断e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是从i号顶点到j号顶点之间的路程。e[i][1]+e[1][j]表示的是从i号顶点先到1号顶点,再从1号顶点到j号顶点的路程之和。其中i是1~n循环,j也是1~n循环,代码实现如下
for(i=1;i<=n;i++)
{
    for(j=1;j<=n;j++)
    {
        if ( e[i][j] > e[i][1]+e[1][j] )
              e[i][j] = e[i][1]+e[1][j];
    }
}

当只允许经过两个顶点时的代码如下:

//经过1号顶点
for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
        if (e[i][j] > e[i][1]+e[1][j])  e[i][j]=e[i][1]+e[1][j];
//经过2号顶点
for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
        if (e[i][j] > e[i][2]+e[2][j])  e[i][j]=e[i][2]+e[2][j];

核心代码只有五行:

for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(e[i][j]>e[i][k]+e[k][j])
                 e[i][j]=e[i][k]+e[k][j];

一句话来概括就是:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。

  • i 出发城市
  • j 到达城市
  • k 中转城市

全部代码

#include <iostream>
using namespace std;

int main()
{
    int datas[105][105];
    int n,m;
    int t1,t2,t3;
    const int inf = 99999;
    cin >> n >> m;
    // 初始化矩阵
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j){
                datas[i][j] = 0;
            }else{
                datas[i][j] = inf;
            }
        }
    }

    // 输入边
    for(int i=1;i<=m;i++){
        cin >> t1 >> t2 >> t3;
        datas[t1][t2] = t3;
    }
    // 核心算法
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(datas[i][j] > datas[i][k] + datas[k][j]){
                    datas[i][j] = datas[i][k] + datas[k][j];
                }
            }
        }
    }
    // 打印结果
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j!=n)
                cout << datas[i][j] << " ";
            else
                cout << datas[i][j] << endl;
        }
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!