最优路径之Dijkstra算法(一)

最优路径之Dijkstra算法(一)
#一、算法原理
在这里插入图片描述

  1. 先根据路径图初始化二维数组的距离(即权值),数组存放对应点到各个节点的距离。
    例如:

    Metro[0]=[0, 2, 3, 6,2048,2048]
    

    表示A到A距离为0,到B距离为2,到C距离为3……。
    添加初始节点A到已确定点中,设置点A的状态为已确定。此时:

    	已确定点数组  S={A},
    	未确定点数组  U={B,C,D,E,F}
    	节点A到各个点的距离  prev={0, 2, 3, 6,∞,∞}
    
  2. 选出当前节点组中未被选中且距离最小的点,加入到已确定路径点中。
    最小值为2,则添加点B到已确定点中。此时:

    	*S={A,B},
    	U={C,D,E,F}
    	prev={0, 2, 3, 6,∞,∞}*
    
  3. 由于点B已确定,这里明显点A 数据组prev也需要更新数据。这里分为几种情况(以到点P为例):
    第一、点A不能到点B能到,最新的距离为A–>B–>P,距离需累加。
    第二、点A,B均能到,则此时需要选出最佳距离,即比较A–>P与A–>B–>P的距离选出最佳路径。
    第三、点A能到B不能到,最新的距离为A–>P,无需更新,则此种情况可不考虑
    第四、点A,B均不能到,故数据无需更新,则此种情况可不考虑
    则更新后的数据为:

     *prev={0, 2, 3,6,6,8}*
    
  4. 重复执行步骤2,将第三个点加入到已确定点中,通过比较未确定的点中点C距离最小,同时更新数据,则有以下数据:

    	S= {A,B,C}
    	U= {D,E,F}
    	prev= {0, 2, 3, 5,6,8}
    

    继续重复执行步骤2,3,直至数组U中没有数据,则此时所有点的最优路径都已经计算完毕,最后得到的数组prev即点A到所有点的最优距离。

    prev= {0, 2, 3, 5,6,8}
    
  5. 至此整个算法计算完成,但随后我发现最后我拿到最优距离之后却无法得到相应的路径,由此需要在计算最优距离过程中同时存储路径。这里我将各个节点中的上一个点存下来,依次上推可以拿到任意点的最优路径

      public class PathNode
     	{
     	    public int curIndex;
     	    public int lastIndex;
     
     	    public PathNode(int _curIndex, int _lastIndex)
     	    {
     	        curIndex = _curIndex;
     	        lastIndex = _lastIndex;
     	    }
     	}
    

#三、实现代码

class Program:MonoBehaviour
{
    int[,] Metro = new int[6, 6] {
        { 0, 2, 3, 6,2048,2048},
        { 2, 0, 2048,2048,4,6},
        { 3, 2048, 0, 2,2048,2048},
        {6, 2048, 2,0,1, 3},
        {2048,4,2048, 1,0, 2048},
        {2048,6,2048, 3,2048, 0}};
    static int row = 6;
    List<int> S = new List<int>(row);//S储存确定最短路径的顶点的下标
    List<int> U = new List<int>(row);//U中存储尚未确定路径的顶点的下标
    private List<PathNode> pathNode = new List<PathNode>();//储存节点的逻辑顺序
    int[] prev = new int[row];//用以存储前一个最近顶点的数据
    bool[] Isfor = new bool[6] { false, false, false, false, false, false };

    public void Start()
    {
        for (int i = 0; i < row; i++)
        {
            pathNode.Add(new PathNode(-1,-1));
        }

    }
    
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.P))
        {
            MyDijkstra(5);
        }
    }

    void MyDijkstra(int _index)
    {
        int pathValue = 0;
        S.Add(_index);
        Isfor[_index] = true;
        for (int i = 0; i < row; i++)
        {
            U.Add(i);
        }
        U.Remove(_index);

        //初始化当前节点数据
        for (int i = 0; i < row; i++)
        {
            prev[i] = Metro[_index,i];
        }

        InitPathNode(pathNode, prev.ToList(), _index);

        while (U.Count>0)
        {
            int m_temp = 2048;
            int curIndex = _index;//当前最小值下标

            //找到最小值,获取下标
            for (int i = 0; i < row; i++)
            {
                if (prev[i] < m_temp && !Isfor[i])
                {
                    m_temp = prev[i];
                    curIndex = i;
                }
            }
           
            pathValue = m_temp;
            Isfor[curIndex] = true;
            S.Add(curIndex);
            U.Remove(curIndex);

            //更新当前节点数据信息
            for (int i = 0; i < row; i++)
            {
                if (!Isfor[i])
                {
                    if (prev[i] < 2048 && Metro[curIndex, i] < 2048)
                    {
                        if (Metro[curIndex, i] + pathValue < prev[i])
                        {
                            prev[i]=Metro[curIndex, i] + pathValue;
                            pathNode[i] = new PathNode(i, curIndex);
                        }
                    }
                    else if (Metro[curIndex, i] < 2048)
                    {
                        prev[i] = Metro[curIndex, i] + pathValue;
                        pathNode[i]=new PathNode(i,curIndex);
                    }
                }
               
            }
        }

        //打印节点的最短路径顺序
        for (int i = 0; i < row; i++)
        {
            string path = "";
            List<int> indexList=new List<int>();

            indexList.Add(i);
            GetPathforIndex(pathNode, indexList, i, _index);
            for (int j = 0; j < indexList.Count; j++)
            {
                if (path=="")
                {
                    path = $"{(indexList[j] + 1)}";
                }
                else
                {
                    path += $"-->{indexList[j] + 1}";
                }
            }
            Debug.LogError($"从点{_index}到点{i + 1}的路径为:{path},距离为:{prev[i]}");
        }
    }

    /// <summary>
    /// 初始化节点的连接关系
    /// </summary>
    /// <param name="_pathNodes"></param>
    /// <param name="_list"></param>
    /// <param name="_index"></param>
    void InitPathNode(List<PathNode> _pathNodes,List<int> _list,int _index)
    {
        for (int i = 0; i < _list.Count; i++)
        {
            if (_list[i]<2048)
            {
                _pathNodes[i]=new PathNode(i,_index);
            }
        }
    }

    /// <summary>
    /// 根据下标获取节点的路径
    /// </summary>
    /// <param name="_pathNodes"></param>
    /// <param name="_path">存储路径节点</param>
    /// <param name="_index"></param>
    /// <param name="_startIndex">起点</param>
    /// <returns></returns>
    List<int> GetPathforIndex(List<PathNode> _pathNodes,List<int> _path ,int _index,int _startIndex)
    {
        _path.Add(_pathNodes[_index].lastIndex);
        if (_pathNodes[_index].lastIndex== _startIndex)
        {
            return _path;
        }
        else
        {
            return GetPathforIndex(_pathNodes, _path, _pathNodes[_index].lastIndex, _startIndex);
        } 
    }
}

public class PathNode
{
    public int curIndex;
    public int lastIndex;

public PathNode(int _curIndex, int _lastIndex)
{
    curIndex = _curIndex;
    lastIndex = _lastIndex;
}
}

猜你喜欢

转载自blog.csdn.net/qq_42914882/article/details/109627410
今日推荐