【校队排位赛#1 A题】 最短路径问题(floyd算法)

在这里插入图片描述

题意:有n个路口,和m条小路,连接两个路口,每条路口都有各自要话费的时间,求从第一个路口到最后一个路口花费的最少时间

写这道题的时候并没有掌握最短路径算法,这道题最后也没能AC。不过也借此机会学一下这类的方法,先从floyd算法开始吧。

该算法解题思路:

1.任意两个路口之间,可能的情况无非是直接一步过去,要么就中间经过若干路口间接到达。那么如果i路口和j路口之间的若有一个中转路口k,i可以先到k再到j。则两点之间的最短时间便是

dp[i][j] = min(dp[i][k]+dp[k][j],dp[i][j])。

然后外层循环遍历k,内层遍历两两端点(路口)即可。

.2. 如果这时候k-j的过程中又有可以中转的路口,而且往后还有好几个类似的呢
这里来个例子讲,以下两两是联通两路口的小路。
5 6
6 7
7 8
8 10
比如我在k=6,要从5到10的时候,也就是拿6做中转,理想上我本应该是dp[5][6]+dp[6][10],应该直接就联通了,但是注意到这里dp[6][10]是没有路的,后面的dp[6][7],dp[7][8]都还没有遍历到,所以在k等于6的时候,dp[5][10]还不能说由5到6再通过6到7、8到10 。

那可是最后就是要dp[5][10]是由5->6->7->8->10的路径联通的呀,怎么实现的呢?
看循环的后续。

当前k=6时,会更新dp[5][7]=dp[5][6]+dp[6][7]。
当k=7时,会更新dp[5][8] = dp[5][7] + dp[7][8]。注意这里的dp[5][7]就是上一步的处理结果。
当k=8时,会更新dp[5][10] = dp[5][8] + dp[8][10]。完成上述的设想。

也就是说两端点间的最小距离会随着中转站的更新而改变/更新。

这也就是floyd算法的精髓了。

还有一种情况是往回折返的,其实就是遍历到低位中转站的时候连接到了高位的端点了,具体如下:
在这里插入图片描述

总体时间复杂度O(n三次方),但是数据规模小可以过。算法本身的思想很棒

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <limits.h>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)&&(n&&m))
    {
        vector<vector<int> > dp(101,vector<int>(101,1e7));
        for(int i=1;i<=m;i++)
        {
              int x,y,time;
              cin>>x>>y>>time;
              dp[x][y] = dp[y][x] = time;
        }
    for(int i=1;i<=n;i++)
    dp[i][i] = 0;

    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                 dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]);
            }
        }
    }
    cout<<dp[1][n]<<endl;
    }
    return 0;
}

发布了32 篇原创文章 · 获赞 23 · 访问量 1816

猜你喜欢

转载自blog.csdn.net/qq_45492531/article/details/104452588
今日推荐