floyed详解[通俗易懂]

floyed详解[通俗易懂]显然Floyed算法是一个简短而好理解的算法,这里指的好理解是因为Floyed的代码长度不大,实在没理解都可以背下来,所以说是好理解,实际上是真的好理解吗?我们来看看最基础的FloyedFloyed是什么?自然是用来求多源最短路的啦,时间效率是O(n^3),有人会问那我不对每个点做一遍SPFA或dijkstra堆优化,时间效率是O(n^2logn)那不是快很多?实际上因为Floyed

大家好,又见面了,我是你们的朋友全栈君。

显然Floyed算法是一个简短而好理解的算法,这里指的好理解是
因为Floyed的代码长度不大,实在没理解都可以背下来,所以说是好理解,实际上是真的好理解吗?我们来看看

最基础的Floyed

Floyed是什么?自然是用来求多源最短路的啦,时间效率是O(n^3),有人会问那我不对每个点做一遍SPFA或dijkstra堆优化,时间效率是O(n^2logn)那不是快很多?实际上因为Floyed常数很小,所以真正比起来,时间效率差不多,所以你是愿意只写5行代码,还是冗杂地打这么长的代码???

Floyed其实用到的是DP的思想f[k,i,j] = min(f[k-1,i,k]+f[k-1,k,j] , f[k-1,i,j]),k是我们用来枚举的断点,说是断点其实就是前K个,只对后面我们将最小环还有其他应用有很大的帮助,因为k是不断递增的,我们可以利用这个性质来做许多题目。通过枚举k,我们可以很快得出任意一点x->y的最短路径。
下面贴上代码

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

是不是简单而好理解???

传递闭包

这是个啥东西?如果我们假设a可以到b,b可以到c,那么a是不是可以到c???实际上这个东西就是指图的连通性,用Floyed处理是不是快很多???比较dfs的话,是优化了很多了。
下面贴上代码

    REP(k,1,n)
    {
        REP(i,1,n)
        {
            REP(j,1,n)
            {
                a[i][j]|=(a[i][k]&a[k][j]);
            }
        }
    }

可以做一下POJ3660Cow Contest是一道裸题
注:&是两个二进制位上有0,就是0,|操作是有1,就是1.

最小环

这个东西怎么说呢???其实我们可以发现如果图里面存在环的话,我们假设i,j间有一条简单路径,如果有环我们可以通过另一个点k到达,是不是跟Floyd算法很相似???所以我们最外层的这个循环,我们用来枚举前k个点,找前k个点中的最小环,后面的Floyd照常进行就可以了,下面的代码还有记录路径,pre[i][j],表示从i到j离j最近的一个点。
POJ1734

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;

#define REP(i,a,b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++i)

inline int read()
{
    char c = getchar();register int fg = 1, sum = 0;
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        sum = sum * 10 + c - '0';
        c = getchar();
    }
    return fg * sum;
} 

int n, m;
int a[200][200],dis[200][200],pre[200][200],path[100000];
#define inf 0x7ffffff

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(a,0,sizeof(a));
        memset(pre,0,sizeof(pre));
        memset(dis,0,sizeof(dis));
        memset(path,0,sizeof(path));
        REP(i,1,n)REP(j,1,n)a[i][j] = inf,pre[i][j] = i;
        REP(i,1,m)
        {
            int x,y,z;
            x = read(), y = read(), z = read();
            a[x][y] = a[y][x] = min(a[y][x],z);
        }
        memcpy(dis,a,sizeof(dis));
        int ans = inf,num = 0;
        REP(k,1,n)
        {
            for(int i = 1; i < k; i++)
            {
                for(int j = i+1; j < k; j++)
                {
                    int tmp = dis[i][j] + a[i][k] + a[k][j];
                    if(tmp < ans)
                    {
                        ans = tmp;
                        num = 0;
                        int now = j;
                        while(now != i)
                        {
                            path[num++] = now;
                            now = pre[i][now];
                        }
                        path[num++] = i,path[num++] = k;
                    }
                }
            }
            REP(i,1,n)
            {
                REP(j,1,n)
                {
                    if(dis[i][j] > dis[i][k]+dis[k][j])
                    {
                        dis[i][j] = dis[i][k] + dis[k][j];
                        pre[i][j] = pre[k][j];
                    }
                }
            }
        }
        if(ans == inf){printf("No solution.\n");continue;}
        int i;
        for(i = 0; i < num-1; i++)printf("%d ",path[i]);
        printf("%d\n",path[i]);
    }
    return 0;
}

其他用途

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;

#define REP(i,a,b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++i)

inline int read()
{
    char c = getchar();register int fg = 1, sum = 0;
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        sum = sum * 10 + c - '0';
        c = getchar();
    }
    return fg * sum;
} 

int n, m;
int a[200][200],dis[200][200],pre[200][200],path[100000];
#define inf 0x7ffffff

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(a,0,sizeof(a));
        memset(pre,0,sizeof(pre));
        memset(dis,0,sizeof(dis));
        memset(path,0,sizeof(path));
        REP(i,1,n)REP(j,1,n)a[i][j] = inf,pre[i][j] = i;
        REP(i,1,m)
        {
            int x,y,z;
            x = read(), y = read(), z = read();
            a[x][y] = a[y][x] = min(a[y][x],z);
        }
        memcpy(dis,a,sizeof(dis));
        int ans = inf,num = 0;
        REP(k,1,n)
        {
            for(int i = 1; i < k; i++)
            {
                for(int j = i+1; j < k; j++)
                {
                    int tmp = dis[i][j] + a[i][k] + a[k][j];
                    if(tmp < ans)
                    {
                        ans = tmp;
                        num = 0;
                        int now = j;
                        while(now != i)
                        {
                            path[num++] = now;
                            now = pre[i][now];
                        }
                        path[num++] = i,path[num++] = k;
                    }
                }
            }
            REP(i,1,n)
            {
                REP(j,1,n)
                {
                    if(dis[i][j] > dis[i][k]+dis[k][j])
                    {
                        dis[i][j] = dis[i][k] + dis[k][j];
                        pre[i][j] = pre[k][j];
                    }
                }
            }
        }
        if(ans == inf){printf("No solution.\n");continue;}
        int i;
        for(i = 0; i < num-1; i++)printf("%d ",path[i]);
        printf("%d\n",path[i]);
    }
    return 0;
}

FLoyd算法用来解决其他的一些多源最短路的问题有想不到的妙处,比如我们所说的洛谷1119灾后重建为例:

B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
题目描述

给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间t[i],你可以认为是同时开始重建并在第t[i]天重建完成,并且在当天即可通车。若t[i]为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。
输入输出格式
输入格式:

输入文件rebuild.in的第一行包含两个正整数N,M,表示了村庄的数目与公路的数量。

第二行包含N个非负整数t[0], t[1], …, t[N – 1],表示了每个村庄重建完成的时间,数据保证了t[0] ≤ t[1] ≤ … ≤ t[N – 1]。

接下来M行,每行3个非负整数i, j, w,w为不超过10000的正整数,表示了有一条连接村庄i与村庄j的道路,长度为w,保证i≠j,且对于任意一对村庄只会存在一条道路。

接下来一行也就是M+3行包含一个正整数Q,表示Q个询问。

接下来Q行,每行3个非负整数x, y, t,询问在第t天,从村庄x到村庄y的最短路径长度为多少,数据保证了t是不下降的。

输出格式:

输出文件rebuild.out包含Q行,对每一个询问(x, y, t)输出对应的答案,即在第t天,从村庄x到村庄y的最短路径长度为多少。如果在第t天无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未修复完成,则输出-1。

输入输出样例
输入样例#1:

4 5
1 2 3 4
0 2 1
2 3 1
3 1 2
2 1 4
0 3 5
4
2 0 2
0 1 2
0 1 3
0 1 4

输出样例#1:

-1
-1
5
4

说明

对于30%的数据,有N≤50;

对于30%的数据,有t[i] = 0,其中有20%的数据有t[i] = 0且N>50;

对于50%的数据,有Q≤100;

对于100%的数据,有N≤200,M≤N*(N-1)/2,Q≤50000,所有输入数据涉及整数均不超过100000。

看数据范围我们很容易想到Floyed,但是怎么做呢???我们不妨假设我们所枚举的k点是指的前k个村庒,由于出题者良心地帮我们排好了顺序,于是我们在Floyd的时候枚举询问,由于你枚举到这个点k,经过k点之前的最短路是被更新出来了的,是不是很明了???

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

#define REP(i,a,b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++i)

inline int read()
{
    char c = getchar();register int fg = 1, sum = 0;
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        sum = sum * 10 + c - '0';
        c = getchar();
    }
    return fg * sum;
}

const int maxn = 100000+10;
int n,m,t[500],qx[maxn],qy[maxn],qt[maxn],dis[500][500];

int main()
{
    n = read(), m = read();
    memset(dis,0x3f,sizeof(dis));
    REP(i,0,n-1)t[i] = read();
    REP(i,1,m)
    {
        int x,y,z;
        x = read(), y = read(), z = read();
        dis[x][y] = z,dis[y][x] = z;
    }
    int q = read();
    REP(i,1,q)
    {
        qx[i] = read(), qy[i] = read(), qt[i] = read();
    }
    int now = 1;
    t[n] = t[n-1] + 1;
    REP(k,0,n-1)
    {
        while(now <= q && t[k] > qt[now])
        {
            int ans = dis[qx[now]][qy[now]];
            if(t[qx[now]] >= t[k] || t[qy[now]] >= t[k])ans = -1;
            printf("%d\n",ans == dis[n][n] ? -1 : ans);
            now++;
        }
        REP(i,0,n-1)
        {
            REP(j,0,n-1)
            {
                if(dis[i][j] > dis[i][k] + dis[k][j])
                    dis[i][j] = dis[i][k] + dis[k][j];
            }
        }
    }
    while(now <= q)
    {
        int ans = dis[qx[now]][qy[now]];
        printf("%d\n",ans == dis[n][n] ? -1 : ans);
        now++;
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/149445.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 非线性最小二乘问题例题_非线性自适应控制算法

    非线性最小二乘问题例题_非线性自适应控制算法摘录的一篇有关求解非线性最小二乘问题的算法–LM算法的文章,当中也加入了一些我个人在求解高精度最小二乘问题时候的一些感触:LM算法,全称为Levenberg-Marquard算法,它可用于解决非线性最小二乘问题,多用于曲线拟合等场合。LM算法的实现并不算难,它的关键是用模型函数 f 对待估参数向量p在其邻域内做线性近似,忽略掉二阶以上的导数项,从而转化为线性最小二乘问题,它具有收敛速度快

  • pytest运行_ios自动清理缓存

    pytest运行_ios自动清理缓存前言pytest运行完用例之后会生成一个.pytest_cache的缓存文件夹,用于记录用例的ids和上一次失败的用例。方便我们在运行用例的时候加上–lf和–ff参数,快速运行上一

  • excel转json操作

    excel转json操作工作中需要用到将从数据库中下载的excel每行数据转成json文件,用于规则回溯,参考网上资料,通过以下代码可实现:importpandasaspdimportnumpyasnpimportjsonimportdatetime#导入数据#由于phone2有缺失值,如果不加converters={‘phone2’:str},导致读入会变成float形式,导致有值的手机号码后会加点0,如13812341234.0data=pd.read_excel(r’C:\Users\

  • Mac Quicktime 录屏带声音[通俗易懂]

    Mac Quicktime 录屏带声音[通俗易懂]最近有录屏的需求,但是Mac大多数录屏软件都收费,之前用Windows时用EV录屏,免费好用,可惜没有Mac版。Mac自带的QuickTime软件虽然能录屏,但是不能录制声音,很苦恼。直到我发现了SoundFlower软件。1、下载安装soundflower给个链接:http://mysoft.6h5.cn/Soundflower-2.0b2.dmg安…

  • vagrant的centos镜像,怎么用root用户登录?

    vagrant的centos镜像,怎么用root用户登录?

  • 云计算基础之如何学习云计算?

    背景随着云计算的普及,越来越多IDC上的网站与应用开始在云上。那么同时对于我们这些IT从业者来说,也面临着加快学习云计算,不被新技术淘汰的挑战。2011年,云计算正式开始发展。今年是2018年了,是云计算发展的第7个年头了。虽然云计算的前景很好,但它的发展也更多地是在商业应用上,还没能达到学习交流分享的层次。云计算的学习路线、书籍、社区与成熟的嵌入式、互联网行业相比,是非常欠缺的!我们这次…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号