帶權重的有向圖求最短路徑


  首先新建一個網圖如下:

  圖的表示法有好多中,最常用的應該是鄰接矩陣與鄰接表。上面的圖,邊很少,用鄰接表來表示就很不錯。

  對於以上圖,可以對象出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里加幾個坐標,就能在地圖上面展示了。下一篇會將它改造成可以在地圖上面展示的路徑規划。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM