zoukankan      html  css  js  c++  java
  • 二十一、所有结点对最短路径问题(弗洛伊德算法)

    弗洛伊德算法介绍

    和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次之后,操作完成!

         单纯的看上面的理论可能比较难以理解,下面通过实例来对该算法进行说明。

    弗洛伊德算法图解

    以上图G4为例,来对弗洛伊德进行算法演示。

    初始状态: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]的大小。

    邻接矩阵:

    class Vertex
    {
    public char label; public boolean wasVisited; public Vertex(char lab)
    { label
    = lab; wasVisited = false; } } class DGraph
    {
    private final int MAX_VERTS = 20; private Vertex vertexList[]; private int adjMat[][]; private int nVerts; public DGraph()
    { vertexList
    = new Vertex[MAX_VERTS]; adjMat = new int[MAX_VERTS][MAX_VERTS]; nVerts = 0; for(int i=0;i<MAX_VERTS;i++) for(int j=0;j<MAX_VERTS;j++) if(i!=j) adjMat[i][j] = Integer.MAX_VALUE; else adjMat[i][j] = 0; } public void addVertex(char lab)
    { vertexList[nVerts
    ++] = new Vertex(lab); } public void addEdge(int start,int end,int weight)
    { adjMat[start][end]
    = weight; //去掉就是有向图 //adjMat[end][start] = weight;//无向图 } /* * floyd最短路径。 * 即,统计图中各个顶点间的最短路径。 * * 参数说明: * path -- 路径。path[i][j]=k表示,"顶点i"到"顶点j"的最短路径会经过顶点k。 * dist -- 长度数组。即,dist[i][j]=sum表示,"顶点i"到"顶点j"的最短路径的长度是sum。 */ public void Floyd()
    {
    int dist[][] = new int[nVerts][nVerts]; int path[][] = new int[nVerts][nVerts]; //初始化 for(int i=0;i<nVerts;i++)
    {
    for(int j=0;j<nVerts;j++)
    { dist[i][j]
    = adjMat[i][j]; path[i][j] = -1; } } // 完成以k为中间点对所有矩阵dist[i][j]的顶点对{i,j}进行检测和修改。 // 如果经过下标为k顶点路径比原两点间路径更短,则更新dist[i][j]和path[i][j] for(int k=0;k<nVerts;k++) for(int i = 0;i<nVerts;i++) for(int j=0;j<nVerts;j++)
    {
    //顶点i与顶点k连接且顶点j与顶点k连接且经过下标为k顶点路径比原两点间路径更短 if(dist[i][k] != Integer.MAX_VALUE && dist[k][j] !=Integer.MAX_VALUE &&
    dist[i][k]+dist[k][j]<dist[i][j])
    { dist[i][j]
    = dist[i][k]+dist[k][j]; path[i][j] = k; } } System.out.println("floyd最短路径结果:"); for(int i=0;i<nVerts;i++)
    {
    for(int j=0;j<nVerts;j++)
    {
    if(i!=j)
    {
    int k = path[i][j]; System.out.print("顶点"+vertexList[i].label+"到顶点"+vertexList[j].label+
    "的路径:"+vertexList[i].label); while(k!=-1)
    { System.out.print(vertexList[k].label); k
    = path[k][j]; } System.out.println(vertexList[j].label+" 最短路径长度:"+dist[i][j]); } } } }
    }
    public class MatrixDG_Floyd
    {
    public static void main(String[] args)
    { DGraph theGraph
    = new DGraph(); theGraph.addVertex('A'); // 0 theGraph.addVertex('B'); // 1 theGraph.addVertex('C'); // 2 theGraph.addVertex('D'); // 3 theGraph.addEdge(0, 1,5); // AB theGraph.addEdge(0, 3,7); // AD theGraph.addEdge(1, 2,4); // BC theGraph.addEdge(1, 3,2); // BD theGraph.addEdge(2, 3,2); // CD theGraph.addEdge(2, 0,3); // CA theGraph.addEdge(2, 1,3); // CB theGraph.addEdge(3, 2,1); // DC theGraph.Floyd(); } }

    floyd最短路径结果:
      顶点A到顶点B的路径:AB      最短路径长度:5
      顶点A到顶点C的路径:ADC     最短路径长度:8
      顶点A到顶点D的路径:AD      最短路径长度:7
      顶点B到顶点A的路径:B       最短路径长度:6
      顶点B到顶点C的路径:BDC     最短路径长度:3
      顶点B到顶点D的路径:BD      最短路径长度:2
      顶点C到顶点A的路径:CA      最短路径长度:3
      顶点C到顶点B的路径:CB      最短路径长度:3
      顶点C到顶点D的路径:CD      最短路径长度:2
      顶点D到顶点A的路径:DCA     最短路径长度:4
      顶点D到顶点B的路径:DCB     最短路径长度:4
      顶点D到顶点C的路径:DC      最短路径长度:1

     

    邻接链表:

    class Vertex
    {
    public char label; public boolean wasVisited; public Edge firstEdge; public Vertex(char lab)
    {
    this.label = lab; this.wasVisited = false; firstEdge = null; } } class Edge
    {
    public int dest; public int weight; public Edge nextEdge; public Edge(int dest,int weight)
    {
    this.dest= dest; this.weight = weight; nextEdge = null; } } class DGraph
    {
    private final int MAX_VERTS = 20;//图的最大顶点数 private int nVerts = 0;//当前顶点数 private Vertex vertexList[];//顶点链表 public DGraph()
    { vertexList
    = new Vertex[MAX_VERTS]; } public void addVertex(char lab)
    { vertexList[nVerts
    ++] = new Vertex(lab); } public void addEdge(int start,int end,int weight)
    { Edge endEdge
    = new Edge(end,weight); Edge edge2 = vertexList[start].firstEdge; if(edge2==null)
    { vertexList[start].firstEdge
    = endEdge; }else
    { while(edge2.nextEdge!=null) edge2 = edge2.nextEdge; edge2.nextEdge = endEdge; } } /* * floyd最短路径。 * 即,统计图中各个顶点间的最短路径。 * * 参数说明: * path -- 路径。path[i][j]=k表示,"顶点i"到"顶点j"的最短路径会经过顶点k。 * dist -- 长度数组。即,dist[i][j]=sum表示,"顶点i"到"顶点j"的最短路径的长度是sum。 */ public void Floyd(){ int dist[][] = new int[nVerts][nVerts]; int path[][] = new int[nVerts][nVerts]; //初始化 for(int i=0;i<nVerts;i++)
    {
    for(int j=0;j<nVerts;j++)
    { dist[i][j]
    = getWeight(i, j); path[i][j] = -1; } } // 完成以k为中间点对所有矩阵dist[i][j]的顶点对{i,j}进行检测和修改。 // 如果经过下标为k顶点路径比原两点间路径更短,则更新dist[i][j]和path[i][j] for(int k=0;k<nVerts;k++) for(int i = 0;i<nVerts;i++) for(int j=0;j<nVerts;j++)
    {
    //顶点i与顶点k连接且顶点j与顶点k连接且经过下标为k顶点路径比原两点间路径更短 if(dist[i][k] != Integer.MAX_VALUE && dist[k][j] !=Integer.MAX_VALUE &&
    dist[i][k]+dist[k][j]<dist[i][j])
    { dist[i][j]
    = dist[i][k]+dist[k][j]; path[i][j] = k; } } System.out.println("floyd最短路径结果:"); for(int i=0;i<nVerts;i++)
    {
    for(int j=0;j<nVerts;j++)
    {
    if(i!=j)
    {
    int k = path[i][j]; System.out.print("顶点"+vertexList[i].label+"到顶点"+vertexList[j].label+
    "的路径:"+vertexList[i].label); while(k!=-1)
    { System.out.print(vertexList[k].label); k
    = path[k][j]; } System.out.println(vertexList[j].label+" 最短路径长度:"+dist[i][j]); } } } } /* * 获取边<start, end>的权值;若start和end不是连通的,则返回无穷大。 */ private int getWeight(int start, int end)
    {
    if (start==end) return 0; Edge currentEdge = vertexList[start].firstEdge; while (currentEdge != null)
    {
    if (end==currentEdge.dest) return currentEdge.weight; currentEdge = currentEdge.nextEdge; } return Integer.MAX_VALUE; } } public class ListDG_Floyd
    {
    public static void main(String[] args)
    { DGraph theGraph
    = new DGraph(); theGraph.addVertex('A'); // 0 theGraph.addVertex('B'); // 1 theGraph.addVertex('C'); // 2 theGraph.addVertex('D'); // 3 theGraph.addEdge(0, 1,5); // AB theGraph.addEdge(0, 3,7); // AD theGraph.addEdge(1, 2,4); // BC theGraph.addEdge(1, 3,2); // BD theGraph.addEdge(2, 3,2); // CD theGraph.addEdge(2, 0,3); // CA theGraph.addEdge(2, 1,3); // CB theGraph.addEdge(3, 2,1); // DC
    theGraph.Floyd(); } }

    floyd最短路径结果:
      顶点A到顶点B的路径:AB      最短路径长度:5
      顶点A到顶点C的路径:ADC     最短路径长度:8
      顶点A到顶点D的路径:AD      最短路径长度:7
      顶点B到顶点A的路径:B       最短路径长度:6
      顶点B到顶点C的路径:BDC     最短路径长度:3
      顶点B到顶点D的路径:BD      最短路径长度:2
      顶点C到顶点A的路径:CA      最短路径长度:3
      顶点C到顶点B的路径:CB      最短路径长度:3
      顶点C到顶点D的路径:CD      最短路径长度:2
      顶点D到顶点A的路径:DCA     最短路径长度:4
      顶点D到顶点B的路径:DCB     最短路径长度:4
      顶点D到顶点C的路径:DC      最短路径长度:1
  • 相关阅读:
    ExtJS4 动态生成grid出口excel(纯粹的接待)
    oracle10g获得Date类型字段无分,秒的解决方案!
    ubuntu13.10 下一个 g++和gcc 4.8不兼容的问题不能被安装
    简单的导航
    Duanxx的C++学习 : 数字转换String
    图widget--jqplot样品和参数描述的简单演示
    m_Orchestrate learning system---三十、项目中的dist文件一般是做什么的
    开放windows服务器端口-----以打开端口8080为例
    phpstudy一个域名配置两个网站(一个是thinkphp5,一个是原生php)
    双向绑定的具体应用场景有哪些
  • 原文地址:https://www.cnblogs.com/xxlong/p/5029745.html
Copyright © 2011-2022 走看看