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

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 10005
int 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值