4

最短経路を計算しようとしています。これは、以下に貼り付けた Dijkstra の実装で機能します。しかし、私は物事をスピードアップしたい。

この実装を使用して、次に進むフィールドを決定します。グラフは、すべてのフィールドが各隣接フィールドに接続されている 2 次元配列を表します。しかし、時間の経過とともに次のことが起こります: いくつかのエッジを削除する必要があります (障害があります)。開始ノードは、時間の経過とともに変化する現在の位置です。

これの意味は:

  • ノードを追加したり、新しいエッジを追加したり、エッジの重みを変更したりすることはありません。唯一の操作はエッジの削除です

  • 開始ノードは時間の経過とともに変化します

質問:

  • グラフの唯一の変更がエッジの削除であることがわかっている場合、最短パスの高速再計算を実行できるアルゴリズムはありますか?

  • 開始ノードが隣接するノードの 1 つだけに変更された場合に、最短パスを高速に再計算できるアルゴリズムはありますか?

  • 別のアルゴリズムが私の問題により適している可能性がありますか?

助けてくれてありがとう

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

public class Dijkstra<T>
{
    private Node<T> calculatedStart;

    private ReadOnlyCollection<Node<T>> Nodes {
        get ;
        set ;
    }

    private ReadOnlyCollection<Edge<T>> Edges {
        get;
        set;
    }

    private List<Node<T>> NodesToInspect {
        get;
        set ;
    }

    private Dictionary<Node<T>, int> Distance {
        get ;
        set ;
    }

    private Dictionary<Node<T>, Node<T>> PreviousNode {
        get;
        set ;
    }

    public Dijkstra (ReadOnlyCollection<Edge<T>> edges, ReadOnlyCollection<Node<T>> nodes)
    {
        Edges = edges;
        Nodes = nodes;
        NodesToInspect = new List<Node<T>> ();
        Distance = new Dictionary<Node<T>, int> ();
        PreviousNode = new Dictionary<Node<T>, Node<T>> ();

        foreach (Node<T> n in Nodes) {
            PreviousNode.Add (n, null);
            NodesToInspect.Add (n);
            Distance.Add (n, int.MaxValue);
        }
    }

    public LinkedList<T> GetPath (T start, T destination)
    {
        Node<T> startNode = new Node<T> (start);
        Node<T> destinationNode = new Node<T> (destination);

        CalculateAllShortestDistances (startNode);

        // building path going back from the destination to the start always taking the nearest node
        LinkedList<T> path = new LinkedList<T> ();
        path.AddFirst (destinationNode.Value);

        while (PreviousNode[destinationNode] != null) {
            destinationNode = PreviousNode [destinationNode];
            path.AddFirst (destinationNode.Value);
        }

        path.RemoveFirst ();

        return path;
    }

    private void CalculateAllShortestDistances (Node<T> startNode)
    {
        if (startNode.Value.Equals (calculatedStart)) {
            return;
        }

        Distance [startNode] = 0;

        while (NodesToInspect.Count > 0) {
            Node<T> nearestNode = GetNodeWithSmallestDistance ();
            // if we cannot find another node with the function above we can exit the algorithm and clear the
            // nodes to inspect because they would not be reachable from the start or will not be able to shorten the paths...
            // this algorithm does also implicitly kind of calculate the minimum spanning tree...
            if (nearestNode == null) {
                NodesToInspect.Clear ();
            } else {
                foreach (Node<T> neighbour in GetNeighborsFromNodesToInspect(nearestNode)) {
                    // calculate distance with the currently inspected neighbour
                    int dist = Distance [nearestNode] + GetDirectDistanceBetween (nearestNode, neighbour);

                    // set the neighbour as shortest if it is better than the current shortest distance
                    if (dist < Distance [neighbour]) {
                        Distance [neighbour] = dist;
                        PreviousNode [neighbour] = nearestNode;
                    }
                }
                NodesToInspect.Remove (nearestNode);
            }
        }

        calculatedStart = startNode;
    }

    private Node<T> GetNodeWithSmallestDistance ()
    {
        int distance = int.MaxValue;
        Node<T> smallest = null;

        foreach (Node<T> inspectedNode in NodesToInspect) {
            if (Distance [inspectedNode] < distance) {
                distance = Distance [inspectedNode];
                smallest = inspectedNode;
            }
        }

        return smallest;
    }

    private List<Node<T>> GetNeighborsFromNodesToInspect (Node<T> n)
    {
        List<Node<T>> neighbors = new List<Node<T>> ();

        foreach (Edge<T> e in Edges) {
            if (e.Start.Equals (n) && NodesToInspect.Contains (n)) {
                neighbors.Add (e.End);
            }
        }

        return neighbors;
    }

    private int GetDirectDistanceBetween (Node<T> startNode, Node<T> endNode)
    {
        foreach (Edge<T> e in Edges) {
            if (e.Start.Equals (startNode) && e.End.Equals (endNode)) {
                return e.Distance;
            }
        }

        return int.MaxValue;
    }
}
4

1 に答える 1

7

グラフの唯一の変更がエッジの削除であることがわかっている場合、最短パスの高速再計算を実行できるアルゴリズムはありますか?

開始ノードが隣接するノードの 1 つだけに変更された場合に、最短パスを高速に再計算できるアルゴリズムはありますか?

これらの質問の両方に対する答えはイエスです。


最初のケースでは、探しているアルゴリズムはLPA*と呼ばれます (あまり一般的ではありませんが、インクリメンタル A* と呼ばれることもあります。その論文のタイトルは古くなっています)。これは A* に対する(かなり複雑な)修正であり、わずかなエッジしか変更されていない場合に最適なパスを高速に再計算できます。

A* と同様に、LPA* には許容距離ヒューリスティックが必要です。そのようなヒューリスティックが存在しない場合は、それを 0 に設定できます。これを A* で行うと、本質的に Djikstra のアルゴリズムになります。これを LPA* で行うと、 DynamicSWSF-SPと呼ばれるあいまいでめったに使用されないアルゴリズムになります。


2 番目のケースでは、 D*-Liteを探しています。ユニットが最初から最後まで移動し、新しい情報が得られる(エッジが追加/削除/変更される)ときに増分パスファインディングを行うのは、 LPA* に対する非常に単純な変更です(少なくとも、LPA* を理解すれば簡単です) 。主に、未知または部分的に既知の地形を横断するロボットに使用されます。


さまざまな経路探索アルゴリズムについて、かなり包括的な回答(質問に論文へのリンクを含む)を書きまし

于 2012-12-30T19:18:35.997 に答える