全源最短路径之弗洛伊德算法(C语言)

Floyd(弗洛伊德)算法

该算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。
时间复杂度为 O(N^3)
空间复杂度为 O(N^2)
Floyd算法蕴涵了动态规划的思想,
简单说:从任意节点i到任意节点j的最短路径存在两种可能

  1. 直接从i到j
  2. i经过若干个节点k到j

所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于Dijkstra算法
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
缺点:时间复杂度比较高,不适合计算大量数据。

算法代码如下:

void Floyd(AdjMatrix *G)
{
    int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];
    int i,j,k;
    //初始化
    for (i=0;inumV;i++)
    {
        for (j=0;jnumV;j++)
        {
            A[i][j]=G->Edge[i][j];
            path[i][j]=-1;
        }
    }
//三重循环,floyd算法核心
    for (k=0;knumV;k++)
    {
        for (i=0;inumV;i++)
        {
            for (j=0;jnumV;j++)
            {
                if (A[i][j]>A[i][k]+A[k][j])
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=k;
                }
            }
        }
    }
    Dispath(A,path,G->numV);//输出函数
}

输出函数包括两部分

void Ppath(int path[][MaxVertices],int i,int j)
{
    int k;
    k=path[i][j];
    if (k==-1)
    {
        return;
    }

    Ppath(path,i,k);
    printf("%d->",k);
    Ppath(path,k,j);
}

void Dispath(int A[][MaxVertices],int path[][MaxVertices],int n)
{
    int i,j;
    for (i=0;ifor (j=0;jif (A[i][j]==INF)
            {
                if (i!=j)
                {
                    printf("从%d%d没有路径\n",i,j);
                }
            }
            else
            {
                printf("  从%d%d的最短路径长度为:%d ",i,j,A[i][j]);
                printf("路径:%d->",i);

                Ppath(path,i,j);//两点i,j之间还有其他中继结点,则循环套用次函数
                printf("%d\n",j);
            }
        }
    }
}

具体代码如下:

#include
#include
#define MaxVertices 100 //假设包含100个顶点
#define MaxWeight 32767 //不邻接时为32767,但输出时用 "∞"
#define MAXV 10
#define INF 32767
typedef struct{ //包含权的邻接矩阵的的定义
    char Vertices[MaxVertices];  //顶点信息的数组
    int Edge[MaxVertices][MaxVertices]; //边的权信息的数组
    int numV; //当前的顶点数
    int numE; //当前的边数
}AdjMatrix;

void CreateGraph(AdjMatrix *G) //图的生成函数
{ 
    int n,e,vi,vj,w,i,j;
    printf("请输入图的顶点数和边数(以空格分隔):");
    scanf("%d%d",&n,&e);
    G->numV=n;G->numE=e;
    for(i=0;i//图的初始化
        for(j=0;jif(i==j)
                G->Edge[i][j]=0;
            else 
                G->Edge[i][j]=32767;
            }
    for(i=0;ifor(i=0;inumV;i++) //将顶点存入数组中
        { 
        printf("请输入第%d个顶点的信息(整型):",i+1);  
      // G->adjlist[i].vertex=getchar(); 
        scanf(" %c",&G->Vertices[i]);
        }
    printf("\n");

    for(i=0;inumE;i++)
    { 
        printf("请输入边的信息i,j,w(以空格分隔):");
        scanf("%d%d%d",&vi,&vj,&w); 
        //若为不带权值的图,则w输入1
        //若为带权值的图,则w输入对应权值

        G->Edge[vi-1][vj-1]=w;//①
        G->Edge[vj-1][vi-1]=w;//②
        //无向图具有对称性的规律,通过①②实现
        //有向图不具备此性质,所以只需要①
    }
}
void DispGraph(AdjMatrix G) //输出邻接矩阵的信息
{ 
    int i,j;
    printf("\n输出顶点的信息(整型):\n");
    for(i=0;iprintf("%8c",G.Vertices[i]);

    printf("\n输出邻接矩阵:\n");
    printf("\t");
    for(i=0;iprintf("%8c",G.Vertices[i]);

    for(i=0;iprintf("\n%8d",i+1);
        for(j=0;jif(G.Edge[i][j]==32767) 
        //两点之间无连接时权值为默认的32767,但输出时为了方便输出 "∞"
            printf("%8s", "∞");
        else
            printf("%8d",G.Edge[i][j]);
        }
        printf("\n");   
    }
}
void Ppath(int path[][MaxVertices],int i,int j)
{
    int k;
    k=path[i][j];
    if (k==-1)
    {
        return;
    }

    Ppath(path,i,k);
    printf("%d->",k);
    Ppath(path,k,j);
}

void Dispath(int A[][MaxVertices],int path[][MaxVertices],int n)
{
    int i,j;
    for (i=0;ifor (j=0;jif (A[i][j]==INF)
            {
                if (i!=j)
                {
                    printf("从%d到%d没有路径\n",i,j);
                }
            }
            else
            {
                printf("  从%d到%d的最短路径长度为:%d ",i,j,A[i][j]);
                printf("路径:%d->",i);

                Ppath(path,i,j);//两点i,j之间还有其他中继结点,则循环套用次函数
                printf("%d\n",j);
            }
        }
    }
}
void Floyd(AdjMatrix *G)
{
    int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];
    int i,j,k;
    //初始化
    for (i=0;inumV;i++)
    {
        for (j=0;jnumV;j++)
        {
            A[i][j]=G->Edge[i][j];
            path[i][j]=-1;
        }
    }
//三重循环,floyd算法核心
    for (k=0;knumV;k++)
    {
        for (i=0;inumV;i++)
        {
            for (j=0;jnumV;j++)
            {
                if (A[i][j]>A[i][k]+A[k][j])
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=k;
                }
            }
        }
    }
    Dispath(A,path,G->numV);//输出函数
}


int main()
{ 
    AdjMatrix G;
    freopen("1.txt","r",stdin);
    CreateGraph(&G);
    Floyd(&G);
    DispGraph(G);
}

注:由于测试输入数据较多,程序可以采用文件输入
5 7
1
2
3
4
5
1 2 2
1 3 4
1 5 2
2 3 1
2 4 6
3 4 2
4 5 3

你可能感兴趣的:(c语言,数据结构与算法)