迪克斯特拉算法

图的最短路径算法,啊?广度优先搜索不就是求最短路径吗?好吧,广度优先搜索是求的最短节点数到达,但是每个节点到每个节点的距离(权重)不一样,就好比东莞到惠州和东莞到北京。所以这时候就要用迪克斯特拉算法了。


class Vertex {//顶点
    public string Name;

    public Vertex(string name) {
        Name = name;
    }
}

class Edge {//边
    public Vertex From;
    public Vertex To;
    public int Weight;

    public Edge(Vertex from, Vertex to, int weight) {
        From = from;
        To = to;
        Weight = weight;
    }
}

class VisitVertex {//用来记录存在的路径和总权重,简称路径
    public int Weight;
    public bool IsVisited;
    public Vertex Vertex;

    public VisitVertex(int weight, bool isVisited,Vertex vertex) {
        Weight = weight;
        IsVisited = isVisited;
        Vertex = vertex;
    }
}

class Program
{

    static Dictionary<string, Edge[]> dict = new Dictionary<string, Edge[]>();
    static void Main(string[] args)
    {
        Vertex O = new Vertex("O");
        Vertex A = new Vertex("A");
        Vertex B = new Vertex("B");
        Vertex C = new Vertex("c");

        //构建权重图
        Edge OA = new Edge(O, A, 6);
        Edge OB = new Edge(O, B, 3);
        dict.Add("O", new Edge[] { OA, OB });
        Edge BA = new Edge(B, A, 2);
        Edge BC = new Edge(B, C, 9);
        dict.Add("B", new Edge[] { BA, BC });
        Edge AC = new Edge(A, C, 1);
        dict.Add("A", new Edge[] { AC });

        SearchLow(C);
        Console.ReadKey();
    }

    static void SearchLow(Vertex x){
        Dictionary<Vertex, Vertex> parent = new Dictionary<Vertex, Vertex>();//保存最短节点与节点的关系
        Dictionary<Vertex, VisitVertex> weight = new Dictionary<Vertex, VisitVertex>();//记录当前最小权重

        //初始化三个字典,起点开始
        //获取到起点开始指向的边
        Edge[] edges;
        dict.TryGetValue("O", out edges);
        foreach (Edge e in edges)
        {
            parent.Add(e.To, e.From);
            weight.Add(e.To, new VisitVertex(e.Weight,false,e.To));
        }


        VisitVertex go = null;
        while ((go = GetLowVertex(weight)) != null) {
            Edge[] edges2;
            dict.TryGetValue(go.Vertex.Name, out edges2);
            if (edges2 == null) break;

            foreach (Edge ee in edges2) {
                int myWeight = go.Weight + ee.Weight;
                VisitVertex orightWeight;
                weight.TryGetValue(ee.To, out orightWeight);
                if (orightWeight == null)
                {
                    //如果没有过该路径,就添加
                    weight.Add(ee.To, new VisitVertex(myWeight, false, ee.To));
                    parent.Add(ee.To, ee.From);
                }
                else {
                    if (orightWeight.Weight > myWeight)
                    {
                        //发现更短的路径,更新权重值,更改为没有访问过,修改父节点(新路径了)
                        orightWeight.Weight = myWeight;
                        orightWeight.IsVisited = false;
                        parent[ee.To] = ee.From;
                    }
                }
                    
            }
        }

           
        //输出路径和权重总值
        VisitVertex finVist;
        weight.TryGetValue(x, out finVist);
        Console.WriteLine("总权重值:" + finVist.Weight);

        Console.WriteLine(x.Name);
        Vertex cur = x;
            
        while (true) {
            Vertex aaa;
            parent.TryGetValue(cur, out aaa);
            cur = aaa;
            if (aaa == null)
            {
                break;
            }

            Console.WriteLine(aaa.Name);
        }
    }

    //获取总权重值最小,又没有被访问过路径
    static VisitVertex GetLowVertex(Dictionary<Vertex, VisitVertex> d) {
        int val = Int32.MaxValue;
        VisitVertex visit = null;
        foreach (var i in d) {
            if (i.Value.IsVisited == false) {
                if (i.Value.Weight < val) {//新路径比旧路径权重值小
                    val = i.Value.Weight;
                    visit = i.Value;
                }
            }
        }

        if (visit != null) {
            //标志该路径以被访问过
            visit.IsVisited = true;
        }
        return visit;
    }
}


这种算法也有限制,就是图中不能出现环图,也不能出现负权重。

详情看:吃菜网-迪克斯特拉算法


首页 我的博客
粤ICP备17103704号