有向无环带权图的最短路径及长度

  给定一个有向无环图的拓扑序列,获取这个序列从起点到序列最后一点的最短路径。

  起点默认为0点(顶点为0,1,2。。。和数组索引对应),序列通过拓扑排序获取。

  下面给出实现,首先是对一个有向无环图进行拓扑排序的类。

package graphics.dag.topologicalsort;

/**
 * 获取一个拓扑序列
 * @author zhangxinren
 *
 */
public class TopologicalSort {
    // 每条边的入度
    private static int[] inDegree;// 邻接表元素个变化,inDegree初始长度也变化
    // 当前可以走的边(入度为0的边)
    private static LinkedNode next;

    public static int[] topologicalSort(int[][] edges) {
        int m = 0;
        int[] result = new int[edges.length];
        inDegree = new int[edges.length];

        for (int i = 0; i < inDegree.length; i++) {
            inDegree[i] = 0;
        }

        for (int i = 0; i < edges.length; i++) {
            for (int j = 0; j < edges[i].length; j++) {
                inDegree[edges[i][j]]++;
            }
        }

        for (int i = 0; i < inDegree.length; i++) {
            if (inDegree[i] == 0) {
                if(next == null){
                    next = new LinkedNode(i);
                }
                else
                {
                    LinkedNode tempNode = new LinkedNode(i);
                    tempNode.next = next.next;
                    next.next = tempNode;
                }
            }
        }

        while (next != null) {// 没有入度为零的顶点时结束
            LinkedNode temp = next.next;// 取出一个入度为零的顶点
            if(temp != null){
                next.next = temp.next;
            }
            else{
                temp = next;
                next = null;
            }

            result[m++] = temp.number;

            int[] tempDegree = edges[temp.number];

            for(int i = 0; i < tempDegree.length; i++){// 更新顶点入度和入度为0的点
                inDegree[tempDegree[i]]--;
                if(inDegree[tempDegree[i]] == 0){
                    LinkedNode tempNode = new LinkedNode(tempDegree[i]);
                    if(null != next){
                        tempNode.next = next.next;
                        next.next = tempNode;
                    }
                    else
                    {
                        next = tempNode;
                    }
                }
            }
        }

        return result;
    }
}

辅助的链表类

package graphics.dag.topologicalsort;

public class LinkedNode {
    int number;
    LinkedNode next;
    public LinkedNode(int number) {
        super();
        this.number = number;
    }
}

 加上一个获取最短路径及最短路径长度的类,类中由起点0到各顶点的最短路径长度及最短路径都可以获取,读者也可以修改起点,获得不同起点到其它点的最短路径。

package graphics.dag.topologicalsort;

/**
 * 有向无环带权图最短路径
 * @author zhangxinren
 *
 */
public class ShortestPathLength {
    // 到顶点的最短路径数组
    private static int[] shortest;
    // 前一个结点到当前结点路径最短时的前一个结点
    private static int[] pred;
    // 顶点邻接表
    private static int[][] edges = {
            {1,2,3},{4},{4,5},{5},{6},{6},{}
    };
    // 边权值的邻接矩阵
    private static int[][] weight = {
            {Integer.MAX_VALUE, 1, 5, 6, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 7, Integer.MAX_VALUE, Integer.MAX_VALUE},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 2, 5, Integer.MAX_VALUE},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 8, Integer.MAX_VALUE},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 4},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 3},
            {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE}
    };

    public static int shortestPathLength(int[][] edges, int[][] weight){
        int n = edges.length;
        shortest = new int[n];
        pred = new int[n];

        // 初始化:认为除起点0的最短路径为0外其它都为无穷大,当前顶点的最短路径的前一个顶点为无(-1)
        for(int i = 0; i < n; i++){
            shortest[i] = Integer.MAX_VALUE;
            pred[i] = -1;
        }

        shortest[0] = 0;

        // 获取一个拓扑序列
        int[] sequence = TopologicalSort.topologicalSort(edges);

        // 处理拓扑序列中的每一个顶点
        for(int i = 0; i < sequence.length; i++){
            int temp = sequence[i];
            // 获取当前顶点为出来边的顶点
            int[] tempDegree = edges[temp];

            // 更新这些顶点的最短距离
            for(int j = 0; j < tempDegree.length; j++){
                int end = tempDegree[j];
                relax(temp, end);
            }
        }

        return shortest[sequence[sequence.length - 1]];
    }

    /**
     * start顶点到它的下一个顶点end,看是否需要更新shortest[end]
     * 在到start顶点最短距离加上start与end的距离小于到end顶点最短距离时,更新最短距离
     * @param start
     * @param end
     * @return
     */
    public static boolean relax(int start, int end){
        if(shortest[start] != Integer.MAX_VALUE && shortest[end] > shortest[start] + weight[start][end]){
            shortest[end] = shortest[start] + weight[start][end];
            pred[end] = start;
            return true;
        }

        return false;
    }

    public static void main(String[] args) {
        // 获取最短路径长度
        int result = shortestPathLength(edges, weight);

        int[] sequence = TopologicalSort.topologicalSort(edges);
        System.out.print("sequence: ");
        for(int i = 0; i < sequence.length; i++){
            System.out.print(sequence[i] + " ");
        }
        System.out.println();
        int end = sequence[sequence.length - 1];
        System.out.println("result: " + result);

        StringBuilder sb = new StringBuilder(end + " ");
        int pre = pred[end];
        while(pre != -1){
            sb.append(pre + " ");
            pre = pred[pre];
        }
        sb.setLength(sb.length() - 1);
        sb.reverse();

        // 打印出最短路径
        System.out.println(sb.toString());

        // 打印出到所有点的最短路径长度
        System.out.println("从0开始的最短路径");
        for(int i = 0; i < edges.length; i++){
            System.out.println(i + ": " + shortest[i]);
        }
    }
}

  下面附上有向无环带权图

  图中基本算法来源于算法基础-打开算法之门一书,根据书中描述加上本人理解加工以代码形式加以实现。理解能力有限,如果看不太懂,可以查看相关资料或者找到书籍自行查看。

  最后打印的结果如下:

sequence: 0 3 2 5 1 4 6
result: 11
0 2 4 6
从0开始的最短路径
0: 0
1: 1
2: 5
3: 6
4: 7
5: 10
6: 11

原文地址:https://www.cnblogs.com/liunianfeiyu/p/9748239.html

时间: 2024-10-11 18:16:03

有向无环带权图的最短路径及长度的相关文章

用无向带权图实现校园导航系统

学校数据结构的课程实验之一. 用到的数据结构:无向带权图 用到的算法:Floyd最短路径算法,深度优先搜索(递归实现) 需求分析: 设计一个校园导航程序,为访客提供各种信息查询服务: 1. 以图中各顶点表示校内各单位地点,存放单位名称,代号,简介等信息:以边表示路径,存放路径长度等相关信息. 2. 图中任意单位地点相关信息的查询. 3. 图中任意单位的问路查询,即查询任意两个单位之间的一条最短的路径. 2. 从图中任意单位地点出发的一条深度优先遍历路径. 主函数: 1 #include <ios

带权图的最短路径算法(Dijkstra)实现

一,介绍 本文实现带权图的最短路径算法.给定图中一个顶点,求解该顶点到图中所有其他顶点的最短路径 以及 最短路径的长度.在决定写这篇文章之前,在网上找了很多关于Dijkstra算法实现,但大部分是不带权的.不带权的Dijkstra算法要简单得多(可参考我的另一篇:无向图的最短路径算法JAVA实现):而对于带权的Dijkstra算法,最关键的是如何“更新邻接点的权值”.本文采用最小堆主辅助,以重新构造堆的方式实现更新邻接点权值. 对于图而言,存在有向图和无向图.本算法只需要修改一行代码,即可同时实

无向带权图的最小生成树算法——Prim及Kruskal算法思路

边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以把边上的权值解释为线路的造价.则最小生成树表示使其造价最小的生成树. 构造网的最小生成树必须解决下面两个问题: 1.尽可能选取权值小的边,但不能构成回路: 2.选取n-1条恰当的边以连通n个顶点: MST性质:假设G=(V,E)是一个连通网,U是顶点V的一个非空子集.若(u,v)是一条具有最小权值的

UVA1599带权图的最短路径以及边的保存方式

这道题目我一开始的想法是还是按照保存父节点的基本思路,但是每次的时候需要挑选每个节点中权值最小的那条边对应的那个点 但是这样会有问题: 第一个问题是:如果某个节点有两条边的权值都是一样的,那么这两个对应的点都必须要入队,那么问题就出现了,如果这俩个节点对应的下一个节点是同一个节点,但是先入队的那个的对应边的权值比较大,后入队的那条边对应的权值比较小,那么在前一个节点访问设置vis后,后面那个节点就不可以再访问了. 其实上面这个情况还是最简单的情况,还有很多更复杂的情况没有考虑到. 所以需要使用刘

Java数据结构——带权图

带权图的最小生成树——Prim算法和Kruskal算法 带权图的最短路径算法——Dijkstra算法 package graph; // path.java // demonstrates shortest path with weighted, directed graphs 带权图的最短路径算法 // to run this program: C>java PathApp ////////////////////////////////////////////////////////////

邻接矩阵表示有向带权图

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef char VertexType[5]; //存储顶点值 #define MaxSize 50 #define INIT 10000 typedef struct //邻接矩阵,存储弧的信息 {     int adj; }ArcNode,AdjMatrix[MaxSize][MaxSize]; typedef struct   //图的类

算法10 之带权图

上一节我们已经看到了图的边可以有方向,这一节里,我们将探讨边的另一个特性:权值.例如,如果带权图的顶点代表城市,边的权可能代表城市之间的距离,或者城市之间的路费,或者之间的车流量等等. 带权图归根究底还是图,上一节那些图的基本操作,例如广度优先搜索和深度优先搜索等都是一样的,在这一节里,我们主要来探讨一下带权图的最小生成树最短路径问题. 最小生成树问题 首先探讨下最小生成树问题,它与上一节所提到的最小生成树不同.上一节的最小生成树是个特例,即所有边的权值都一样.那么算法如何设计呢?建议用优先级队

[算法] 带权图

最小生成树(Minimum Span Tree):对于带权无向连通图.所有节点都连通且总权值最小.应用:电缆布线.网络.电路设计 找V-1条边,连接V个顶点,总权值最小 切分定理(Cut Property):给定任意切分,横切边中权值最小的边必属于最小生成树 切分:把图中节点分为两部分 横切边:边的两个端点属于切分的不同两边 证明:反证法,假设横切边中一条权值不是最小的边属于最小生成树,给生成树添加横切边中权值最小的边形成环,删掉权值不是最小的边打破环得到新的权值更小的生成树,与假设矛盾 实现:

7-9-有向图无环拓扑排序-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第7章  图 - 有向无环图拓扑排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceStack.c.ALGraph.c