最短路径Dijkstra备忘

参考:

http://2728green-rock.blog.163.com/blog/static/43636790200901211848284/

http://hi.baidu.com/chin/blog/item/93aed933e6772443ad4b5f88.html

描述:

Dijkstra算法思想为:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将 加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

 

说明:

V表示点集合,E表示边集合,图G=(V,E)表示图是由点集合与点之间的连线组成,如V={a,b,c,d}表示图G有a,b,c,d四个点,E={(a,b),(a,c),(c,d),(b,d)},表示图有a-b,a-c等边,一般<a,b>这样的尖括号表示有向边,(a,b) 这样的圆括号表示无向边。

 

有点集合V={a,b,c,d,e,f}

S表示已计算出最短路径(假设a为源点)的顶点集合 ,U表示除S中点以外的点的集合,U中每个点ui都对应着一个距离值a--ui(存在a到ui的边),a--ui这个距离值可取无穷大(两点没有直接连线),或是经过S中的某一个或多个点a--si--ui的距离值。

1.S中第一个加入的点是a,加入a后a-a的距离是零,满足S中的点必需是计算出最短路径的要求.

2.接着在U中选择最短的a-ui,假设ui是d,将d加入集合S,此时S={a,d},然后尝试使用a-d-ui调整U={c,d,e,f}中每个点a--ui的距离(如果通过新加的d点使a--ui距离变短).

3.重复步骤2,直到U集合中没有点,算法结束S中将是a到任意点的最短距离。

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LycorisRadiata.UI.Craft
{
    public class Dijkstra
    {
        #region Model
        /// <summary>
        /// node
        /// </summary>
        public class N
        {
            public int Id { get; set; }
            public String Name { get; set; }
            public String Flag { get; set; }
            public String ExtendProperty { get; set; }
            public List<E> Edges { get; set; }
            public N()
            {
                Edges = new List<E>();
            }
            public N(int id)
                : this()
            {
                this.Id = id;
            }

        }
        /// <summary>
        /// edge
        /// </summary>
        public class E
        {
            public int ToId { get; set; }
            public decimal Len { get; set; }
            public E()
            {

            }
            public E(int toId, decimal len)
                : this()
            {
                this.ToId = toId;
                this.Len = len;
            }

        }
        public class NodeDistance
        {
            public int NodeId { get; set; }
            public int PreNodeId { get; set; }
            /// <summary>
            /// HasSelected=true时
            /// 这里记录了从出发点经过PreNodeId到该节点(NodeId)
            /// 最短距离--是累加的距离
            /// </summary>
            public decimal Distance { get; set; }
            /// <summary>
            /// 是否已经在最优集合里了
            /// </summary>
            public bool HasSelected { get; set; }
            public NodeDistance()
            {
                HasSelected = false;
            }
            public NodeDistance(int nodeId, int preNodeId, decimal len)
            {
                this.NodeId = nodeId;
                this.PreNodeId = preNodeId;
                this.Distance = len;
            }
        }

        /// <summary>
        /// 路径
        /// </summary>
        public class Route
        {
            /// <summary>
            /// StartIdToEndId
            /// </summary>
            public int StartId { get; set; }
            public int EndId { get; set; }

            public List<N> Nodes { get; set; }
            public String Way { get; set; }
            public decimal Distance { get; set; }
            public void CalcDistance()
            {

                var prevNode = Nodes[0];
                var dist = 0.0m;
                var sb = new StringBuilder();
                for (int i = 0; i < Nodes.Count; i++)
                {
                    var curNode = Nodes[i];
                    if (prevNode.Id == curNode.Id) continue;
                    var edge=prevNode.Edges.FirstOrDefault(e => e.ToId == curNode.Id);
                    dist +=edge.Len;
                    prevNode = curNode;
                    sb.AppendFormat("-{0}->[{1}]",  edge.Len,curNode.Id);
                }
                Distance = dist;
                Way ="[" + Nodes[0].Id +"]"  + sb.ToString() ;



            }
            public Route()
            {
                Nodes = new List<N>();
            }


        }
        #endregion

        private decimal[,] _G = null;
        private List<NodeDistance> _VSet;
        public List<Route> Calc(List<N> nodes, N start)
        {
            //InitGMatrix(nodes);完全用不到
            
            _VSet = new List<NodeDistance>();
            for (int i = 0; i < nodes.Count; i++)
            {
                _VSet.Add(new NodeDistance(i, start.Id, decimal.MaxValue));
            }

            var curDistInfo = _VSet[start.Id];//当前考察节点
            curDistInfo.Distance = 0;
            curDistInfo.HasSelected = true;
            var curNode = start;


            var iteration_max = 1000000;
            var iteration_count = 0;
            while (_VSet.Any(ent => ent.HasSelected == false))
            {
                iteration_count++;
                if (iteration_count > iteration_max) throw new Exception("算法迭代超过设置值!");

                #region 使用curNode调整VSet距离
                foreach (var edge in curNode.Edges)
                {

                    var dist = curDistInfo.Distance;
                    var inspectDist= _VSet.FirstOrDefault(ent =>ent.HasSelected==false && ent.NodeId == edge.ToId);//跳过已经标记的点
                    if (inspectDist == null) continue;
                    var newDist=dist+edge.Len;
                    if (inspectDist.Distance > newDist)
                    {
                        inspectDist.PreNodeId = curDistInfo.NodeId;
                        inspectDist.Distance = newDist;
                        
                    }

                }
                #endregion

                curDistInfo= _VSet.Where(ent => ent.HasSelected == false).OrderBy(ent => ent.Distance).FirstOrDefault();
                if (curDistInfo == null) break;
                curNode = nodes.FirstOrDefault(ent => ent.Id == curDistInfo.NodeId);
                curDistInfo.HasSelected = true;


            }
            var rList = new List<Route>();
            #region 生成结果
            foreach (var item in _VSet)
            {
                var curDistEnt = item;
                var route=new Route();
                rList.Add(route);
                route.StartId=start.Id;
                route.EndId = curDistEnt.NodeId;
                var node = nodes.FirstOrDefault(ent => ent.Id == curDistEnt.NodeId);
                route.Nodes.Add(node);
                while (curDistEnt.PreNodeId != start.Id)
                {
                    
                    node = nodes.FirstOrDefault(ent => ent.Id == curDistEnt.PreNodeId);
                    route.Nodes.Add(node);
                    curDistEnt = _VSet.FirstOrDefault(ent => ent.NodeId == curDistEnt.PreNodeId);
                }
                route.Nodes.Add(start);//加入起始节点
                route.Nodes.Reverse();
                route.CalcDistance();

            }
            #endregion
            return rList;
        }

        private void InitGMatrix(List<N> nodes)
        {
            _G = new decimal[nodes.Count, nodes.Count];
            for (int row = 0; row < nodes.Count; row++)
            {
                for (int col = 0; col < nodes.Count; col++)
                {
                    if (row == col)
                    {
                        _G[row, col] = 0;
                    }
                    else
                    {
                        _G[row, col] = decimal.MaxValue;
                    }
                }
            }
            #region 构建GMatrix
            foreach (var node in nodes)
            {
                var row = node.Id;
                foreach (var edge in node.Edges)
                {
                    var col = edge.ToId;
                    if (_G[row, col] > 0 && _G[row, col] != decimal.MaxValue && _G[row, col] != edge.Len)
                    {
                        throw new Exception(string.Format("边{0}-{1} 的数据有不一致的情况", row, col));
                    }
                    _G[row, col] = edge.Len;
                }
            }
            #endregion
        }
    }
}
View Code
            var nodes=new List<Dijkstra.N>();
            #region 构建Node列表
            var node0 = new Dijkstra.N(0);
            node0.Edges.Add(new Dijkstra.E(1, 4));
            node0.Edges.Add(new Dijkstra.E(7, 8));
            nodes.Add(node0);

            var node1 = new Dijkstra.N(1);
            node1.Edges.Add(new Dijkstra.E(0, 4));
            node1.Edges.Add(new Dijkstra.E(2, 8));
            node1.Edges.Add(new Dijkstra.E(7, 11));
            nodes.Add(node1);

            var node2 = new Dijkstra.N(2);
            node2.Edges.Add(new Dijkstra.E(1, 8));
            node2.Edges.Add(new Dijkstra.E(3, 7));
            node2.Edges.Add(new Dijkstra.E(8, 2));
            node2.Edges.Add(new Dijkstra.E(5, 4));
            nodes.Add(node2);

            var node3 = new Dijkstra.N(3);
            node3.Edges.Add(new Dijkstra.E(2, 7));
            node3.Edges.Add(new Dijkstra.E(4, 9));
            node3.Edges.Add(new Dijkstra.E(5, 14));
            nodes.Add(node3);

            var node4 = new Dijkstra.N(4);
            node4.Edges.Add(new Dijkstra.E(3, 9));
            node4.Edges.Add(new Dijkstra.E(5, 10));
            nodes.Add(node4);

            var node5 = new Dijkstra.N(5);
            node5.Edges.Add(new Dijkstra.E(3, 14));
            node5.Edges.Add(new Dijkstra.E(4, 10));
            node5.Edges.Add(new Dijkstra.E(2, 4));
            node5.Edges.Add(new Dijkstra.E(6, 2));
            nodes.Add(node5);

            var node6 = new Dijkstra.N(6);
            node6.Edges.Add(new Dijkstra.E(5, 2));
            node6.Edges.Add(new Dijkstra.E(7, 1));
            node6.Edges.Add(new Dijkstra.E(8, 6));
            nodes.Add(node6);

            var node7 = new Dijkstra.N(7);
            node7.Edges.Add(new Dijkstra.E(0, 8));
            node7.Edges.Add(new Dijkstra.E(1, 11));
            node7.Edges.Add(new Dijkstra.E(6, 1));
            node7.Edges.Add(new Dijkstra.E(8, 7));
            nodes.Add(node7);

            var node8 = new Dijkstra.N(8);
            node8.Edges.Add(new Dijkstra.E(2, 2));
            node8.Edges.Add(new Dijkstra.E(6, 6));
            node8.Edges.Add(new Dijkstra.E(7, 7));
            nodes.Add(node8);

            #endregion
            var srv = new Dijkstra();
            var list= srv.Calc(nodes, node5);
            foreach (var way in list)
            {
                Console.WriteLine(String.Format("{0}->{1},距离:{2},路径:{3}",way.StartId,way.EndId,way.Distance,way.Way));
            }
View Code

 

原文地址:https://www.cnblogs.com/wdfrog/p/1935574.html