最短路 - floyd 【 理解 + 例题 】 更新 ing...

    看着巨巨们越来越牛逼,渣渣表示,只能做渣渣了、、 整个暑假,就是不停地擦手机屏幕,微博,空间,贴吧,朋友圈,一刷就是一天了,轮流刷,花式刷,刷刷刷、、

    距离上一篇博文,好久好久了吧,今天来写一篇水的,算是交差了、、=。=

    floyd算法的核心就是dp,对图中的对在 i 和 j 之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3)。对于稠密图,效率高于dijkstra。(主要用于初始化吧、)

    核心代码如下,你也许会说,才三个for,so easy 啊,但是到应用的时候,也会稍微复杂一点。这也是我学的第一个最短路算法,现在看来没有当初认为的那么简单了、、

   

for(int k = 1; k <= n; k ++)
     for(int i = 1; i <= n; i ++)
         for(int j = 1; j <= n; j ++)
             dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    相关应用 : 有向图:    ①求任意2点间最短路径  ②求最小环(可判断负圈,检查dis[i][i])   ③求传递闭包
                       无向图:(无负权边):  ①求任意2点间最短路径  ②求最小环

    下面就来几道题目好了

     HDU 3631 Shortest Path (普通的应用)   http://acm.hdu.edu.cn/showproblem.php?pid=3631
     该题算是floyd算法的一个应用了吧,但和模版差不多。。 就是当q 操作的时候,只有当mark 过,才可以加入floyd 的过程中,如果没有mark过,就当做不存在这个点。另外需要注意的是,该题是有向图,一开始模版的无向图直接代进去,错了好多次、、、其实该题的思路很清晰、、、

    

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define INF 1<<29
#define N 310

bool mark[N];  // 标记是否被询问过
int dis[N][N];
int n, m, q;

void floyd(int k)     // 此题中,只有当加入k 这个点时,才算是图中有这个点,不然即使输入过也没用
{
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < n; j ++)
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}

void init(int n)
{
    int i, j;
    for(i = 0; i < n; i ++)
        for(j = 0; j < n; j ++)
            dis[i][j] = (i == j) ? 0 : INF; // 从一个点到本身的距离是0,否则初始化的时候,设为无限大,代表这两点不连通
}

int main()
{
    int u, v, w;
    int icase = 1;
    while(~scanf("%d%d%d",&n, &m, &q))
    {
        if(n == 0 && m == 0 && q == 0)
            break;
        memset(mark, 0, sizeof(mark));  
        init(n);
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d%d%d",&u, &v, &w);
            if(w < dis[u][v])
                dis[u][v] = w;
        }
        int t, a, b;
        if(icase > 1)     // 虽然这不是重点,但是对于害怕 PE 的coder 来说,也需要注意以下、、
            printf("\n");
        printf("Case %d:\n", icase ++);
        while(q --)
        {
            scanf("%d",&t);
            if(t == 0)
            {
                scanf("%d",&a);
                if(mark[a] == 1)
                {
                    printf("ERROR! At point %d\n",a);
                    continue;
                }
                mark[a] = 1;
                floyd(a);
            }
            else
            {
                scanf("%d %d",&a, &b);
                if(!mark[a] || (!mark[b]))
                    printf("ERROR! At path %d to %d\n",a, b);
                else if(dis[a][b] == INF)
                    printf("No such path\n");
                else
                    printf("%d\n",dis[a][b]);

            }
        }
    }
    return 0;
}

    HDU 1599 find the mincost route  求无向图的最小环 http://acm.hdu.edu.cn/showproblem.php?pid=1599

   

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define INF 1<<29
#define N 105

int mat[N][N],dis[N][N];
int minloop;

void floyd(int n)
{
    int i, j, k;
    for(k = 1;k <= n; k ++)
    {
        for(i = 1; i <= n; i ++)
            for(j = 1; j <= n; j ++)
                if(i!=j && i!=k && j!=k && dis[i][j] + mat[j][k] + mat[k][i] < minloop)
                    minloop = dis[i][j] + mat[j][k] + mat[k][i];
        for(i = 1; i <= n; i ++)
            for(j = 1; j <= n; j ++)
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    }
}

void init(int n)
{
    int i, j;
    minloop = INF;
    for(i = 1; i <= n; i ++)
        for(j = 1; j <= n; j ++)
            mat[i][j] = mat[j][i] = dis[i][j] = dis[j][i] = INF;
}

int main()
{
    int i,n,m,u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        init(n);
        for(i = 1; i <= m; i ++)
        {
            scanf("%d%d%d",&u, &v, &w);
            if(w < mat[u][v])
                mat[u][v] = mat[v][u] = dis[u][v] = dis[v][u] = w;
        }
        floyd(n);
        if(minloop == INF)
            printf("It's impossible.\n");
        else
            printf("%d\n",minloop);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值