最短路径基础算法——弗洛伊德

问题 A(1171): 【基础算法】最短路径问题
时间限制: 1 Sec 内存限制: 64 MB
题目描述
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
输入
第1行:1个整数n
第2…n+1行:每行2个整数x和y,描述了一个点的坐标
第n+2行:1个整数m,表示图中连线的数量
接下来有m行,每行2个整数i和j,表示第i个点和第j个点之间有连线
最后1行:2个整数s和t,分别表示源点和目标点
输出
第1行:1个浮点数,表示从s到t的最短路径长度,保留2位小数(如果到达不了,输出极大值0x7f对应的double类型的值)
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

样例输出

3.41

思路点拔: 一道最短路的入门题,本题可以使用弗洛伊德算法;下面我就详细的推导一下弗洛伊德算法
介绍
和Dijkstra算法一样,弗洛伊德(Floyd)算法也是一种用于寻找给定的加权图中顶点间最短路径的算法。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。基本思想 通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入一个矩阵S,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。 假设图G中顶点个数为N,则需要对矩阵S进行N次更新。初始时,矩阵S中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞。 接下来开始,对矩阵S进行N次更新。第1次更新时,如果"a[i][j]的距离" > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示"i与j之间经过第1个顶点的距离"),则更新a[i][j]为"a[i][0]+a[0][j]"。 同理,第k次更新时,如果"a[i][j]的距离" > “a[i][k]+a[k][j]”,则更新a[i][j]为"a[i][k]+a[k][j]"。更新N次之后,操作完成! 单纯的看上面的理论可能比较难以理解,下面通过实例来对该算法进行说明。
实例分析
最短路径基础算法——弗洛伊德_第1张图片
以上图G4为例,来对弗洛伊德进行算法演示。
最短路径基础算法——弗洛伊德_第2张图片
初始状态:S是记录各个顶点间最短路径的矩阵。 第1步:初始化S。 矩阵S中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞。实际上,就是将图的原始矩阵复制到S中。 注:a[i][j]表示矩阵S中顶点i(第i个顶点)到顶点j(第j个顶点)的距离。第2步:以顶点A(第1个顶点)为中介点,若a[i][j] > a[i][0]+a[0][j],则设置a[i][j]=a[i][0]+a[0][j]。 以顶点a[1]6,上一步操作之后,a[1][6]=∞;而将A作为中介点时,(B,A)=12,(A,G)=14,因此B和G之间的距离可以更新为26。同理,依次将顶点B,C,D,E,F,G作为中介点,并更新a[i][j]的大小。
代码实现

#include
#include
#include
const int maxn=105;
double jl(double a,double b,double c,double d) //两点距离公式,注意坐标是double 
{
    return sqrt(pow((a-b),2)+pow((c-d),2));
}
int main()
{
    int n,m,c,d,p,q;
    double a[maxn],b[maxn],dis[maxn][maxn]; //dis是邻接矩阵 
    memset(dis,0x7f,sizeof(dis)); //将初值弄成极大值 
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%lf %lf",&a[i],&b[i]); //输入每个点的坐标 
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&c,&d); //输入两个相连的点 
        dis[c][d]=dis[d][c]=jl(a[c],a[d],b[c],b[d]); //拿到两个点的距离,由于是无向图,所以要对称“存储”
    } 
    scanf("%d %d",&p,&q);
    for(int k=1;k<=n;k++) //fluyd算法,注意,k必须是最外层循环 
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i!=j&&i!=k&&j!=k) //更新 
                {
                    if(dis[i][j]>dis[i][k]+dis[k][j]) //动态规划思想,记录每一个阶段的最小值 
                    {
                        dis[i][j]=dis[i][k]+dis[k][j];
                    }
                }
            }
        }
    }
    printf("%.2lf\n",dis[p][q]); //输出结果 
    return 0;
}

你可能感兴趣的:(图论)