在附加条件下寻找最快路径

时间:2013-01-06 16:33:14

标签: c# algorithm dijkstra

我想知道,如果Dijkstra的算法在无向图中有多个直接连接时能正常工作。

E.g:

enter image description here

我想用Dijkstra找到最快的路径,但还有另外一个条件。边缘上所有additional_data的总和不能是> = x。所以,如果它出现了重量:3的边缘使用错误,我的程序将尝试第二条边缘。

编辑: 我的任务是找到最快的路径,条件是边缘additional_data的总和不能高于x。你能告诉我如何处理这个问题吗?

edit2 :(设置赏金)

我一直在研究互联网,直到我发现这个link。 有关如何做我要求的事情的解释。 (中上层 acapite)

我正试图以某种方式使用它2天,但我担心我不能正确理解这个算法。我想请你们中的一些人帮助我解决这个问题,向我解释一些例子(几个第一步)。这是一个例子:

enter image description here

8 个答案:

答案 0 :(得分:8)

我认为您可以修改Dijkstra的算法来处理这个问题。 Dijkstra的算法基本上通过逐步构建一个列出每个节点的最短路径的表来工作。您将构建一个表,列出以给定成本的每个节点的最短路径。或者更确切地说,以给定的成本或更低的成本,即在给定的预算下。

更正式地说,您可以将原始图表转换为另一个图表,然后将Dijkstra应用于该图表。假设additional_data cost始终为整数,则转换为:

  1. 获取每个原始节点n并为c的每个整数值创建一组节点(n,c),从0到预算值(您可以容忍的additional_data的最大总和)
  2. 取每个原始连接n1 - > n2与权重w和additional_data a,并创建一组从每个节点(n1,c)到节点(n2,c + a)的连接,每个节点的权重为w
  3. 原始图模型中的节点位于空间中。变换后的图模型中的节点位于状态空间中,状态变量是位置,到目前为止所花费的预算金额。

    如果你想以预算x从A到Z,那么你只需使用Dijkstra算法找到从(A,0)到其中一个节点(Z,c <= x)的路线。

    编辑:我已经实施了修改后的Dijkstra算法:https://bitbucket.org/twic/roadsproblem。它的症结在src/solver.py

答案 1 :(得分:5)

以下是对您找到的算法如何处理示例问题的解释。

问题是找到node onenode four之间的最短路径,并且额外条件是沿途的累计费用不应超过7

我们想要找到的解决方案是首先从node one转到节点node two,距离为190,费用为4。然后使用距离node two和费用node four的路径从195转到3。总的来说,路径的距离为385,费用为7

第1步

那么算法如何找到这个?第一步是像你一样设置矩阵minArray(i,j)。数组的元素(i,j)包含您必须前往节点j且距离恰好为i的距离。

Original array.

开始时没有访问过的元素,因为我们从node one开始7“monies”,左上角的元素设置为零。上表中的空白对应于数组中设置为infinity的值。

第2步

接下来,我们找到数组的最低值,这是位置(remaining money, node) = (7,1)处的零。此元素设置为visited(使用与visitedArray相同大小的矩阵minArray跟踪元素的状态,这意味着我们选择了node one 。现在,通过遍历相应的边缘,所有连接到node one的节点都会使用值进行更新。

Array one.

此处minArray(6,3) = 191表示我们已经191距离node three,而我们留下的钱是6,因为我们付了一笔费用1到达那里。同样,minArray(3,2)设置为190。红色方块表示访问了元素(7,1)

第3步

现在我们再次找到最低的未访问元素(minArray(3,2) = 190),将其设置为visited并更新连接到它的所有元素。这意味着累积距离,并通过从当前值中减去成本来计算剩余资金。

Array two.

请注意,从node one返回node two费用太贵了。

第4步

下一步,选择minArray(6,3) = 191就是这样。

Array three.

第5步

三步后,阵列看起来像这样。这里选择了等于382的两个元素和等于383的元素。请注意,元素的值仅在其改善(即低于)当前值时才会更新。

Array four.

第6步

阵列继续填满,直到所有元素都被访问过或仍然具有无限值。

Array 5.

最后一步

最后一步是通过找到第四列的最低值来找到总距离。我们可以看到最小值minArray(0,4) = 385对应于正确的解决方案。

注意:如果第四列的所有值都是无限的,则意味着没有有效的解决方案。该算法还指定如果第四列中有多个相等和最小距离的值,则选择最便宜的值。

答案 2 :(得分:1)

我不认为Dijkstra的算法是解决这个问题的好方法,因为所需的距离不仅是源节点和目的地。这是一个基于A *搜索算法的解决方案。\

首先,根据weight执行FolydWarshall,然后基于additional_data,为图中的每个节点对获得最少weight和最少additional_data

  FloydWarshall(Weights);
  FloydWarshall(Additional_datas);

其次,我们基于优先级队列执行A *搜索,其元素如下面的结构(使用c代码作为示例。)优先级队列将自动获得所有候选中的weights_sum。 weights_expected是通过当前节点到目标节点的路径的最佳猜测,而weights_now是当前权重

  struct NODE
    {
        int node;
        int weights_expected;
            int weights_now;
        int additional_datas_now;
            bool visited;
    };
    bool operator < (const NODE &A,const NODE &B)
    {
        return A.weights_expected>B.weights_expected || (A.weights_expected==B.weights_expected && 
   A.additional_datas_now>B.additional_datas_now);
    }

在A *搜索算法中,

1) we first put the source node into priority queue. 
  2) while Priority Queue is not empty:
        Set **A** equal to the head of priority queue and pop out the head of priority queue. 
        A.visited=True;
        if A is the destination node **Dest**, **return** A.weights_expected. 
        For each neighbors **B** of node **A**, 
          if A.visited==False **and** A.additional_datas_sum+|AB|.additional_data+Additional_datas[B][Dest]<=x, 
               1) B.additional_datas_now=A.additional_datas_now+|AB|.additional_data;    
               2) B.weights_now=A.weights_now+|AB|.weight;
               3) B.weights_expected=B.weights_now+Weights[B][Dest];
               3) push node B into priority Queue. 
   3) Print "Do not find a proper path" //if code came to here, that means the if in 2) do not return a value. 

A *搜索仍然是NP难,因为在最坏的情况下,它必须搜索每个可能的路径。然而,它将比简单的DFS搜索快得多,并执行大量的搜索路径切割。

答案 3 :(得分:1)

您可以在节点之间创建一个0成本的副本,以添加第二条可能的路径。

像这样(伪代码)

Node 1____
|         |
|path1    |
|cost=3   |path2 cost=5
|         |
Node 2____/

成为这个:

Node 1____cost=0____Node 1a
|         path 1a     |
|path1                |path2
|cost=3               |cost=5
|                     |
Node 2________________/

不确定这是否有效,但这是一个想法。

答案 4 :(得分:1)

附加条件将打破Dijkstra。可以这样想:如果图中的路径A-> B和图中的边B-> C,那么涉及B的最短路径A-> C肯定是A的最小路径。 - &GT; B-&℃。在您的情况下,这种情况不成立,因为虽然A-> B和B-> C可能有效,但A-> B-> C可能无效。

好的,这就是你拿一张纸然后试试这个的地方。

如果您查看图表,并假设您想从(1)到(4),请注意如何通过引入以下边缘来消除(3):

  • (1) - &gt;(4),[390,2]
  • (1) - &gt;(2),[383,3]
  • (2) - &gt;(4),[391,3]

一旦消除了所有边缘但是直线,问题变得更加容易:对于每个节点,您可以跟踪到达目标需要多少[距离,额外]。您无需存储其他&gt;最大或'剩余额外'&lt; 0,因为那不是一个可行的解决方案。此外,如果您有多个相等的距离,则应保留最小距离。

现在最好的解决方案是在最后一个节点(或第一个节点中具有最小距离的解决方案,具体取决于您的订购方式)。如果你在路上,你一直指着你如何到达那里(例如,如果更新矩阵中的值也存储了使其发生变化的元素),你也可以回溯路径。

在这里您应该注意,当问题处于非消除形式时,您可以使用您建议的矩阵:x轴作为节点,y轴作为“每个节点列表”。

应该这样做。

答案 5 :(得分:1)

你可以使用bellman-ford算法,假设你的附加数据是bellman-ford算法中的边数参数

答案 6 :(得分:1)

这个问题是NP完全的。没有算法比多人解释的算法更有效(Tom Anderson,user1884905)。

证明: 通过减少非负数的子集和。

获取子集和(N个数字)的实例A.构造一个图形,其中有N + 1个节点。对于节点i和i + 1,制作2个路径,一个具有权重= 0,additional_data = A [i],另一个具有权重= A [i],additional_data = 0。选择x(additional_data总和的限制)。

观察算法必须最小化权重之和,因此它还将最大化additional_data的总和。因此,所选择的第一种路径将是与子集和问题的结果中的数字相关联的路径。

答案 7 :(得分:0)

您的附加条件使问题变得更加困难。看看它,我认为你唯一可以做的就是找出源和目标之间的所有可能路径,按总边重对它们进行排序,然后如果你的附加条件成立则逐个检查。

但是,找到两个顶点之间所有可能路径的问题是NP-Hard。 DFS的略微修改版本可能能够解决问题,但可能并非在所有情况下都可以。