zoukankan      html  css  js  c++  java
  • 多源最短路径--flody算法

    floyd算法

    适用范围:

    >floyd算法主要用于求多(全)源最短路径的算法,可以适用于无向图和有向图,也可以用于负权的最短路径问题(虽然复杂度回比较高) >时间复杂度:O(n^3);空间复杂度:O(n^2);

    基本思想:

    与Warshall算法一样,首先我们也要确定一个点k,但是这个点不是起始点,而是中间点。通过Floyd算法计算图G=(V,E)最短路径问题的时候,我们首先要引入邻接矩阵W来表示,用来计算每个相邻点的距离,W0也就是我们的已知条件

    我们在进行Floyd算法的时候,不停的更新矩阵W。当我们根据某些规律(通常是从1到n)变化到中间点k的时候,W[i][j]代表从i到j仅用前k个点得到的最短路径,若W[i,j]>W[i,k]+W[j,k],则矩阵W中的W[i,j]需要改变成W[i,k]+W[k,j],完成从Wk-1到Wk的转换,到

    当然,如果要求具体路径,可以用Path矩阵记录中转点

    大佬的解释

    优点及其局限性

    优点:

    ①. 思路简洁,代码实现容易,核心代码只有五行:

    for(int k = 1; k <= n; k++)
    {
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(W[i][j]>W[i][k]+W[k][j])
    				W[i][j] = min(W[i][j], W[i][k]+W[k][j]);
    		}
    	}
    }
    

    为什么k要在最外层?

    ②. 适合处理稠密图的多源路径问题

    缺点:

    ①. 复杂度较高(O(n^3)),不适合处理单源路径问题
    ②. 对于存在“负权回路”(或者叫“负权环”)的图无能为力(因为带有“负权回路”的图没有最短路)

    例如下面这个图就不存在1号顶点到3号顶点的最短路径。因为1->2->3->1->2->3->…->1->2->3这样路径中,每绕一次1->-2>3这样的环,最短路就会减少1,永远找不到最短路。

    实战

    1. 基础:最好的地方Best Spot




    思路:要求出到F个给定点(牧场)的路径平均最短的点(牧场),只需要找出到这F个点(牧场)路径之和最短的点(牧场),只需要用floyd算法求出所有两两点(牧场)之间的最短路径,再通过枚举各个点(牧场)来得到路径和最小的那个点即可

    AC代码:

    #include <stdio.h>
    
    #define MAX 100000000
    
    int min(int a, int b)
    {
        return a<b?a:b;
    }
    int main(void)
    {
        int p, f, c; //p个点,f个给定点, c个(等价)关系
        scanf("%d %d %d",&p,&f,&c);
        int like[f+1], W[p+1][p+1];
        for(int i = 1; i <= f; i++)
            scanf("%d",like+i);
        for(int i = 1; i <= p; i++)
        {
            for(int j = 1; j <= p; j++)
            {
                W[i][j] = MAX;
            }
            W[i][i] = 0;  //自己到自己的路径费用显然应为0
        }
        int a, b, t;
        for(int i = 1; i <= c; i++)
        {
            scanf("%d %d %d",&a,&b,&t);
            W[a][b] = t;
            W[b][a] = t;        //等价关系的赋初值
        }
        for(int k = 1; k <= p; k++)
        {
            for(int i = 1; i <= p; i++)
            {
                for(int j = 1; j <= p; j++)
                {
                    W[i][j] = min(W[i][j], W[i][k]+W[k][j]);
    	            //W[j][i] = W[i][j];
    	            //等i和j值互换时自然可以求出,故这里的W[j][i] = W[i][j]可加也可不加
                }
            }
        }
        int minnum = MAX, sum = 0, ans = 0;
        for(int i = 1; i <= p; i++)
        {
            sum = 0;
            for(int j = 1; j <= f; j++)
            {
                sum+=W[i][like[j]];
            } 
            if(sum<minnum)  //枚举各个点并比较
            {
                minnum = sum;
                ans = i;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    2. 变化:牛栏Cow Hurdles




    题目意思是:找出i连通到j的途中最高的那个栏杆,我们想让这个最高的杆子尽量矮(小),如果不连通就输出-1

    思路:由于求的是连通路径中所有栏杆最高的那个,那么首先肯定不能像以往一样把不连通的设置为无穷大(相比较其他的是无穷大就行),我这里是设置为-1,除此之外只要多加几个是否连通的判断即可

    AC代码:

    #include <stdio.h>
    
    int min(int a, int b)
    {
        return a<b?a:b;
    }
    int max(int a, int b)
    {
        if(a==-1)
            return b;
        if(b==-1)
            return a; //保证输出的是连通的那个
        return a>b?a:b;//都连通再输出尽量高的栏杆
    }
    int main(void)
    {
        int n, m, t;    //n个点, m个关系, t个询问
        scanf("%d %d %d",&n,&m,&t);
        int W[n+1][n+1];
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
                W[i][j] = -1;     //不连通默认赋值为-1,因为结果要求的是最高栏杆值,所以不能令不连通的路设置为无穷大
        }
        int s, e, h;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d %d %d",&s,&e,&h);
            W[s][e] = h;         //赋值初始邻接矩阵
        }
        for(int k = 1; k <= n; k++)
        {
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= n; j++)
                {
                    if(W[i][j]==-1) //如果仅仅用前k-1个点不能使i到j连通
                    {
                        if(W[i][k]!=-1&&W[k][j]!=-1) //并且通过中转点k可以连通的话
                            W[i][j] = max(W[i][k], W[k][j]);
                    }
                    else //如果仅仅用前k-1个点能使i到j连通
                    {
                        if(W[i][k]!=-1&&W[k][j]!=-1) //并且通过中转点k可以连通的话
                            W[i][j] = min(W[i][j], max(W[i][k], W[k][j]));
                    }
                }
            }
        }
        int a, b;
        for(int i = 1; i <= t; i++) //对每个询问解答
        {
            scanf("%d %d",&a, &b);
            printf("%d
    ",W[a][b]);
        }
        return 0;
    }
    
  • 相关阅读:
    字母统计
    特殊乘法
    一年的第几天
    找中位数
    查找学生信息
    Hdu 1009 FatMouse' Trade
    Hdu 1012 u Calculate e
    Hdu 1005 Number Sequence
    Hdu 1008 Elevator
    Hdu 1003 Max Sum
  • 原文地址:https://www.cnblogs.com/SpicyArticle/p/11549668.html
Copyright © 2011-2022 走看看