zoukankan      html  css  js  c++  java
  • 带权重的有向图求最短路径

      首先新建一个网图如下:

      图的表示法有好多中,最常用的应该是邻接矩阵与邻接表。上面的图,边很少,用邻接表来表示就很不错。

      对于以上图,可以对象出3个类。图、节点、边。3个实体类代码如下:

      边Edge:

        public class Edge
        {
            public string StartNodeID
            {
                get;
                set;
            }
            public string EndNodeID
            {
                get;
                set;
            }
            public int Weight
            {
                get;
                set;
            }
        }

      节点Node:

        public class Node
        {
            private string id;
            private IList<Edge> edgeList;
            public Node(string nid)
            {
                id = nid;
                edgeList = new List<Edge>();
            }
    
            public string Id
            {
                get
                {
                    return id;
                }
            }
    
            public IList<Edge> EdgeList
            {
                get
                {
                    return edgeList;
                }
            }
        }

      图Graph:

        public class Graph
        {
            public List<Node> NodeList = new List<Node>();
        }

      由于要求的就是最短路径,路径对象模拟如下:

        public class Path
        {
            public string CurrentNodeId;
            public bool IsProcessed = false;
            public int Weight = 99999999;
            public List<string> PathNodeList = new List<string>();
        }

      最短路径计算类:

        /// <summary>
        /// 计算最短路径帮助类
        /// </summary>
        public class CaculateHelper
        {
            private Dictionary<string, Path>  dicPath = new Dictionary<string, Path>();
            public Dictionary<string, Path> DicPath
            {
                get
                {
                    return dicPath;
                }
            }
    
            public void IniFirstNode(Graph graph, string StartNodeId)
            {
                Node OriginNode = null;
                foreach (Node node in graph.NodeList)
                {
                    if (node.Id == StartNodeId)
                    {
                        OriginNode = node;
                    }
                    else
                    {
                        Path path = new Path();
                        path.CurrentNodeId = node.Id;
                        dicPath.Add(path.CurrentNodeId, path);  //初始化A->到所有边都是默认的Path 99999999
                    }
                }
    
                //如果有A直接进入的边,则设置为相应权重值,和记录下路径
                foreach (Edge edge in OriginNode.EdgeList)
                {
                    Path path = new Path();
                    path.CurrentNodeId = edge.EndNodeID;
                    path.Weight = edge.Weight;
                    path.PathNodeList.Add(edge.StartNodeID);
                    dicPath[path.CurrentNodeId] = path;
                }
            }
    
            public Node GetFromNodeMinWeightNode(Graph graph)
            {
                Node CNode = null;
                KeyValuePair<string, Path> KVPPath = dicPath.Where(m => !m.Value.IsProcessed).OrderBy(m => m.Value.Weight).FirstOrDefault();
                if (KVPPath.Key != null)
                {
                    CNode = graph.NodeList.FirstOrDefault(m => m.Id == KVPPath.Value.CurrentNodeId);
                }
                return CNode;
            }
    
            /// <summary>
            /// 计算最短权值路径
            /// </summary>
            public void CatelateMinWeightRoad(Graph graph)
            {
                //取从第一个点出发,最小权值且未被访问果的节点的点
                Node CNode = GetFromNodeMinWeightNode(graph);
                //这段代码是核心 循环每个顶点,看看经过该顶点是否会让权值变小,如果会则存起此路径。直到再未访问过的点
                while (CNode != null)
                {
                    Path CurrentPath = dicPath[CNode.Id];
                    foreach (Edge edge in CNode.EdgeList)
                    {
                        Path TargetPath = dicPath[edge.EndNodeID];
                        int tempWeight = CurrentPath.Weight + edge.Weight;
                        if (tempWeight < TargetPath.Weight)
                        {
                            TargetPath.Weight = tempWeight;
                            TargetPath.PathNodeList.Clear();
    
                            for (int i = 0; i < CurrentPath.PathNodeList.Count; i++)
                            {
                                TargetPath.PathNodeList.Add(CurrentPath.PathNodeList[i].ToString());
                            }
    
                            TargetPath.PathNodeList.Add(CNode.Id);
                        }
                    }
    
                    //标志为已处理
                    dicPath[CNode.Id].IsProcessed = true;
                    //再次获取权值最小的点
                    CNode = GetFromNodeMinWeightNode(graph);
                }
            }
        }

      主控制台程序:

        class Program
        {
            static void Main(string[] args)
            {
                Graph graph = new Graph();
    
                #region 初始化一个图的 节点和边
    
                //***************** B Node *******************
                Node aNode = new Node("A");
                graph.NodeList.Add(aNode);
                //A -> B
                Edge aEdge1 = new Edge();
                aEdge1.StartNodeID = aNode.Id;
                aEdge1.EndNodeID = "B";
                aEdge1.Weight = 10;
                aNode.EdgeList.Add(aEdge1);
                //A -> C
                Edge aEdge2 = new Edge();
                aEdge2.StartNodeID = aNode.Id;
                aEdge2.EndNodeID = "C";
                aEdge2.Weight = 20;
                aNode.EdgeList.Add(aEdge2);
                //A -> E
                Edge aEdge3 = new Edge();
                aEdge3.StartNodeID = aNode.Id;
                aEdge3.EndNodeID = "E";
                aEdge3.Weight = 30;
                aNode.EdgeList.Add(aEdge3);
    
                //***************** B Node *******************
                Node bNode = new Node("B");
                graph.NodeList.Add(bNode);
                //B -> C
                Edge bEdge1 = new Edge();
                bEdge1.StartNodeID = bNode.Id;
                bEdge1.EndNodeID = "C";
                bEdge1.Weight = 5;
                bNode.EdgeList.Add(bEdge1);
                //B -> E
                Edge bEdge2 = new Edge();
                bEdge2.StartNodeID = bNode.Id;
                bEdge2.EndNodeID = "E";
                bEdge2.Weight = 10;
                bNode.EdgeList.Add(bEdge2);
    
                //***************** C Node *******************
                Node cNode = new Node("C");
                graph.NodeList.Add(cNode);
                //C -> D
                Edge cEdge1 = new Edge();
                cEdge1.StartNodeID = cNode.Id;
                cEdge1.EndNodeID = "D";
                cEdge1.Weight = 30;
                cNode.EdgeList.Add(cEdge1);
    
                //***************** D Node *******************
                Node dNode = new Node("D");
                graph.NodeList.Add(dNode);
    
                //***************** C Node *******************
                Node eNode = new Node("E");
                graph.NodeList.Add(eNode);
    
                //E -> D
                Edge eEdge1 = new Edge();
                eEdge1.StartNodeID = eNode.Id;
                eEdge1.EndNodeID = "D";
                eEdge1.Weight = 20;
                eNode.EdgeList.Add(eEdge1);
    
                //E -> F
                Edge eEdge2 = new Edge();
                eEdge2.StartNodeID = eNode.Id;
                eEdge2.EndNodeID = "F";
                eEdge2.Weight = 20;
                eNode.EdgeList.Add(eEdge2);
    
                //***************** F Node *******************
                Node fNode = new Node("F");
                graph.NodeList.Add(fNode);
    
    
                #endregion
    
                //计算从A -> C的最短权值路线
                string StartNodeId = "A";
                string EndNodeId = "F";
    
                CaculateHelper CH = new CaculateHelper();
                //第一步,初始化初始化源点 A 到 其他各点的 权重以及 路径(完成 A->B A->C A->E A->D 边权重,与A无直接边的则默认99999999)
                CH.IniFirstNode(graph, StartNodeId);
                //第二步,从权重最小的点开始,一直到权值最大的点
                CH.CatelateMinWeightRoad(graph);
    
                #region 以下与计算无关,仅仅用于将结果打印出来
                Path ShowPath = CH.DicPath[EndNodeId];
                foreach(string MiddleNodeId in ShowPath.PathNodeList)
                {
                    Console.WriteLine(MiddleNodeId);
                }
                Console.WriteLine(ShowPath.Weight);
                #endregion
    
                Console.ReadKey();
            }
        }

      不要小看上面这几行代码,哥看了好久才看懂,如果Node里加几个坐标,就能在地图上面展示了。下一篇会将它改造成可以在地图上面展示的路径规划。

  • 相关阅读:
    面向接口编程详解(二)——编程实例
    面向接口编程详解(一)——思想基础
    设计模式之面向接口编程
    EF数据注解
    很多人不知道可以使用这种 key 的方式来对 Vue 组件时行重新渲染
    这是最新的一波Vue实战技巧,不用则已,一用惊人
    Node.js 进阶-你应该知道的 npm 知识都在这
    Vue响应式原理
    eslint规则
    简述vue-cli中chainWebpack的使用方法
  • 原文地址:https://www.cnblogs.com/kissdodog/p/5437897.html
Copyright © 2011-2022 走看看