训练第五周之只有五行的Floyd算法

来源:互联网 发布:雅思作文知乎simon 编辑:程序博客网 时间:2024/05/19 07:08

http://developer.51cto.com/art/201403/433874.htm(作者:坐在马桶上看算法)

个人觉得这个大神写得很好,所以放在这里参考一下


Floyd算法:

一、定义:

Floyd算法是用于解决多源最短路径的算法,即可以求任意两个节点之间的最短路径,由Robert W. Floyd(罗伯特·弗洛伊德)于1962年发表在“Communications of the ACM”上。

二、描述:

这里写图片描述

对于任意两个节点来说,假设不能经过第三个节点,那么最短路径就是初始赋值

这里写图片描述

假设只能通过第一个节点,那么比较从i到j与从i到1再到j的路径长度,取最小,由此更新所有节点间的路径

这里写图片描述

再看假设只能通过第一、二个节点,更新所有节点间路径

只能通过1、2个节点

能通过第一、二、三个节点…直到能通过所有节点

只能通过1、2、3节点 能通过所有节点

最后dist[i][j]存的就是从i到j的最短路径长度。

三、步骤:

1.定义dist[maxn][maxn]来记录最短路径,先根据题意初始化,有权值则赋权值,无权值则赋无穷,节点相同赋0

2.三重循环更新节点间的最短路径dist[i][j],需记住中间节点的循环在最外层

3.最后dist[i][j]存的就是从i到j的最短路径长度

四、核心代码(只有五行):

for(k=1;k<=s;k++)    for(i=1;i<=s;i++)        for(j=1;j<=s;j++)            if(dist[i][j]>dist[i][k]+dist[k][j])                dist[i][j]=dist[i][k]+dist[k][j];

五、例题:

1、find the safest road-hdu1596

题目概述:8600进行星球旅游,希望路线的安全系数最高,求任意输入的两个星球之间的最高安全系数。因为起点终点不确定,所以很明显是求多源最短路径,用Floyd算法。

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<iomanip>#include<algorithm>using namespace std;double dist[1005][1005]={0};int main(){    int n,i,j,k;    while(scanf("%d",&n)!=EOF)    {        for(i=0;i<n;i++)            for(j=0;j<n;j++)                scanf("%lf",&dist[i][j]);        for(k=0;k<n;k++)            for(i=0;i<n;i++)                for(j=0;j<n;j++)                    if(dist[i][k]*dist[k][j]>dist[i][j])                        dist[i][j]=dist[i][k]*dist[k][j];        int q;        scanf("%d\n",&q);        while(q--)        {            int b,c;            scanf("%d%d",&b,&c);            if(dist[b-1][c-1])                printf("%.3lf\n",dist[b-1][c-1]);            else                printf("What a pity!\n");        }    }    return 0;}

2、HDU Today-hdu2112

题目概述:帮徐总坐公交,输出能到达目的地的最短时间,不能就输出-1。这个题目已经指出了起点和终点,应该是用dijkstra算法的,但是我比较喜欢Floyd些,另外这个题目还有几个坑点,如起点终点相同、起点被孤立、输出-1等等,但在我看来最坑最坑的地方就是题目明明是个有向图,却非得弄成无向图来做,害我wa了七八次!!!

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define INF 99999999#define maxn 10005int t;                //记录出现的总站数char station[160][35];//用来记录出现过的站名int dist[160][160];   //用来记录节点间的最短路径int record(char x[])//将站名编号,出现过就返回对应编号,没出现过就用station[][]记录,并编号,方便后面用Floyd{    int i=1;    for(i=1;i<t;i++)    {        if(strcmp(station[i],x)==0)            break;    }    if(i==t)    {        strcpy(station[i],x);        t++;    }    return i;}int main(){    int n,i,j,k,c,station1,station2,s=160;    char start[35],End[35];    char a[35],b[35];    while(scanf("%d",&n)!=EOF&&n!=-1)    {        t=1;//每一次都将总站数初始为1        memset(station,0,sizeof(station));//每一次都将station[][]清空        scanf("%s%s",start,End);        for(i=1;i<=s;i++)            for(j=1;j<=s;j++)                if(i==j) dist[i][j]=0;                 else dist[i][j]=INF;//初始dist        for(i=1;i<=n;i++)        {            scanf("%s%s%d",a,b,&c);            station1=record(a);            station2=record(b);            if(c<dist[station1][station2]&&c<dist[station2][station1])/*我觉得这里应该加上判断,不过不加也没错,可能是题目规定了没有多重边吧,也可能是杭电比较水*/                dist[station1][station2]=dist[station2][station1]=c;/*这题题目有毒,明明是个有向图非要按无向图来做*/        }        station1=record(start);        station2=record(End);        for(k=1;k<=s;k++)//Floyd算法            for(i=1;i<=s;i++)                for(j=1;j<=s;j++)                    if(dist[i][j]>dist[i][k]+dist[k][j])                        dist[i][j]=dist[i][k]+dist[k][j];        if(dist[station1][station2]<INF)            printf("%d\n",dist[station1][station2]);        else            printf("-1\n");    }    return 0;}
0 0
原创粉丝点击