【ACM之路】4.最短路算法 - Floyd算法

Flody算法是一种多源最短路径算法。(即每个点到其他点之间的最短路径)

1.问题引出

有四个城市1,2,3,4,  8条街道(分别表明了路径长度),要求每个城市到其他城市的最短路径。

用 n 代表城市个数,m 代表城市道路的个数。

图片摘自《啊哈算法》,如有侵权请联系删除。

 2.思路引导

首先我们来存储这些数据,用一个二维数组,map[105][105].(map[ i ][ j ],代表从地点 i 到 j 的距离是多少,

1.建立数组map[105][105],并初始化数组。

(这里我们定义两种距离,自己到自己的距离为0,自己到其他人的距离为 ∞,如1到1为0, 1到2,3,4为 ∞。)

int map[105][105]; //创建数组



for(int i=1;i<=n;i++)               //n代表城市个数
    for(int j=1;j<=n;j++)
    {
        if(i==j)map[i][j] = 0;
        else map[i][j] = INF        //这里的INF是预定义的  ,如 #define INF 65535
创建数组
初始化

 

 

 

 

 

 

 2.输入数据:

首先输入测试用例的个数,

//n代表城市个数,m代表道路个数。
while(cin >> n >> m){
    /*
        初始化代码。。。
    */

    //Input data
    for(int i=0;i<m;i++)    //m条道路
    {
        int a,b,c;
        cin >> a >> b >> c;
        if(c < map[a][b])       //本来可以不用写这一行的,但是某些测试用例,会给你重复数据,
            map[a][b] = c;      //如2 3 2,2 3 4(2到3的距离为2,2到3的距离为4,直接改就error
    }

输入后结果如图:

3.直接Flody算法。

当然算法前先介绍一下基本知识,缩短路径可以用三个点来缩短,需要松弛操作。

松弛点

比如从1->2的距离为2, 3->1的距离为7, 3->2未直接连接,距离为无穷大,则以1为松弛点,3->2的距离可以改为更小的数9(2+7),直接更新。其他点类似。

/code形式:map[3][2] = map[3][1] + map[1][2];/

1松弛点,3->2更新为9

同样的,还可以以1为松弛点对其他道路进行更新。1松弛完后,结果如下:

同理,可以对2,3,4点分别当作松弛点进行松弛,松弛操作每次需要3个点即可。 

于是可以将代码整理为如下:其中k点为松弛点,如k = 1,i = 3, j = 2,则是以1为松弛点,从3到2 判断是否能够松弛,如果距离比松弛后的距离大,则将距离改为松弛后的距离。

即 if ( map[i][j] > map[i][k] + map[k][j] )           map[i][j]  =  map[i][k] + map[k][j];

Floyd完整代码:

void Floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(map[i][j] > map[i][k]+map[k][j])
                    map[i][j] = map[i][k]+map[k][j];
}

4.输出距离:

比如题目让输出,从1点到4点的距离,则直接输出map数组的内容,即 map[1] [4].

cout << map[1][4] << endl;

3测试题与完整代码:

测试题:HDU - 2544 最短路

完整代码:

#include <iostream>
#define INF 655355
using namespace std;

int mp[105][105];
int n,m;      ///n表示地点的个数,m表示路线个数
void Floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(mp[i][j] > mp[i][k]+mp[k][j])
                    mp[i][j] = mp[i][k]+mp[k][j];

}

int main()
{
    while(cin >> n >> m)
    {
        if(m==0&&n==0)break;

        //初始化
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j)
                    mp[i][j] = 0;
                else
                    mp[i][j] = INF;
            }
        }

        //INPUT
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin >> a >> b >> c;
            ///防止有重复路径
            if(c < mp[a][b])
                mp[a][b] = mp[b][a] = c;
        }

        //Floyd
        Floyd();


        //Output
        cout << mp[1][n] <<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值