最短路径之Floyd(弗洛伊德)算法,以及显示完整路径

简介:

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。

我的上一篇文章讲的dijjstra算法,是图中某一个顶点,到其它顶点之间的最短路径.时间复杂度为O(n2),是单源最短路径

而Floyd算法,是图中每一个顶点,到其它顶点之间的最短路径.时间复杂度为O(n3).也被称为多源最短路径问题.

算法思想:

1,逐个顶点试探

2,从Vi到Vj的所有可能存在的路径中

3,选出一条长度最短的路径

求最短路径步骤:

初始时设置一个n阶方阵,令其对角线元素为0,若存在弧<Vi,Vj>,则对应元素为权值;否则为∞

逐步试着在原直接路径中增加中间顶点,若加入中间顶点后路径变短,则修改之;否则,维持原值.所有顶点试探完毕,算法结束

举个实例:

 1,加入顶点a:

  2,加入顶点b:

   3,加入顶点c:

 

4,加入顶点d:

 5,加入顶点e:

 这个就是具体的一个过程,下面是实现代码:

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#define MAXINT 10000
int get_index(char* arr, char ch)//得到输入的字符在数组中的下标
{
    int i = 0;
    for(i = 0; i < MAXINT;i++)
    {
        if(arr[i] == ch)return i;
    }
    return -1;
}
void FindPath(int MiddleVer[MAXSIZE][MAXSIZE],int start, int end, char vertex[MAXSIZE])//寻找经过的结点
{
    if(MiddleVer[start][end] == MAXINT)//说明start和end,两个顶点是直连的,中间没有别的顶点了
    {
        printf("%c",vertex[start]);
    }
    else
    {   //如果tart和end,两个顶点之间还有别的顶点
        FindPath(MiddleVer, start, MiddleVer[start][end], vertex);//则递归查找,从start位置到中间点位置的路径
        start = MiddleVer[start][end];
        while(MiddleVer[start][end] != MAXINT)//再查找从中间点位置到end位置之间的路径.
        {//这里为什么不也用递归?是因为顺序的问题.这里如果也用递归,找出来的顶点顺序相反了.
            printf("%c",vertex[MiddleVer[start][end]]);
            start = MiddleVer[start][end];
        }
    }
    printf("%c",vertex[end]);
}

void floyd()
{
    int m,n,i,j,k;
    char ch1,ch2;
    char vertex[MAXSIZE];//顶点数组
    int arcs[MAXSIZE][MAXSIZE];//图的邻接矩阵,存储每一条边的权值
    int MiddleVer[MAXSIZE][MAXSIZE];//存储每条边之间的中间点的下标,如果没有中间点,则值为MAXINT
    for(i = 0;i < MAXSIZE;i++)
    {
        for(j = 0;j < MAXSIZE;j++)
        {
            if(i == j)arcs[i][j] = 0;
            else arcs[i][j] = MAXINT;//初始化每一条边
            MiddleVer[i][j] = MAXINT;//初始化每一条边的中间点
        }
    }
    printf("请输入顶点数和弧的数目:>");
    scanf("%d%d",&m,&n);
    for(i = 0;i < m;i++)
    {
        printf("请输入每一个顶点的名称:>");
        getchar();
        scanf("%c",&vertex[i]);
    }
    for(i = 0;i < n;i++)
    {
        printf("请输入每一条边,以及边的权值:>");
        getchar();
        scanf("%c%c %d",&ch1,&ch2,&k);
        arcs[get_index(vertex,ch1)][get_index(vertex,ch2)] = k;//把输入的每一条边的权值存储到邻接矩阵arcs中
        //如果是无向网,则要把对称点也赋上权值
        //arcs[get_index(vertex,ch2)][get_index(vertex,ch1)] = k;
    }
    //FLOYD算法核心
    for(k = 0;k < m;k++)
    {
        for(i = 0; i < m;i++)
        {
            for(j = 0;j < m;j++)
            {
                if(arcs[i][j] > arcs[i][k]+arcs[k][j])
                {
                    arcs[i][j] = arcs[i][k]+arcs[k][j];
                    MiddleVer[i][j] = k;
                }
            }
        }
    }
    for(i = 0; i < m;i++)
    {
        for(j = 0;j < m;j++)
        {
            if(i != j && arcs[i][j] != MAXINT)
            {
                printf("%c->%c的权值为%d,路径为:>",vertex[i],vertex[j],arcs[i][j]);
                FindPath(MiddleVer, i,j,vertex);
                printf("\n");
            }
        }
    }
}
int main()
{
    floyd();
    return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值