简体   繁体   English

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

[英]Finding fastest path at additional condition

I'm wondering, if Dijkstra's algorithm will work properly when there is more than one direct connection in an undirected graph. 我想知道,如果Dijkstra算法在无向图中有多个直接连接时能够正常工作。

Eg: 例如:

在此输入图像描述

I want to use Dijkstra to find the fastest path but, there's an additional condition. 我想用Dijkstra找到最快的路径,但还有另外一个条件。 Sum of all additional_data on the edges can't be >= x. 边上的所有additional_data的总和不能是> = x。 So, if it came out that edge with weight: 3 was wrong to use, my program would try with the 2nd edge. 因此,如果它出现了重量:3的边缘使用错误,我的程序将尝试第二个边缘。

edit: My task is to find the fastest path, under the additional condition that the sum of additional_data from the edges can not be higher than x. 编辑:我的任务是找到最快的路径,在附加条件下,来自边缘的additional_data的总和不能高于x。 Could you tell me how to handle this problem? 你能告诉我如何处理这个问题吗?

edit2: (setting up on a bounty) edit2 :(设置赏金)

I've been researching internet alot untill I've found this link . 我一直在研究互联网,直到我发现这个链接 There's an explanation of how to do the thing I'm asking for. 有关如何做我要求的事情的解释。 ( Upper-Intermediate acapite) (中上层 acapite)

I'm trying to use it somehow for 2 days now but I'm worried I do not understand this algorithm correctly. 我试图以某种方式使用它2天,但我担心我不能正确理解这个算法。 I'd like to ask some of you to help me with this problem, by explaining me a little more on example (few first steps). 我想请你们中的一些人帮助我解决这个问题,向我解释一些例子(几个第一步)。 Here's the example: 这是一个例子:

在此输入图像描述

I think you can modify Dijkstra's algorithm to handle this. 我想你可以修改Dijkstra的算法来处理这个问题。 Dijkstra's algorithm basically works by incrementally building a table listing the shortest path to every node. Dijkstra的算法基本上通过逐步构建一个列出每个节点的最短路径的表来工作。 You would instead build a table listing the shortest path to every node at a given cost . 您将构建一个表,列出以给定成本到达每个节点的最短路径。 Or rather, at a given cost or less, ie on a given budget. 或者更确切地说,以给定的成本或更低的成本,即在给定的预算下。

More formally, you can transform your original graph into another graph, and then apply Dijkstra to that graph. 更正式地说,您可以将原始图形转换为另一个图形,然后将Dijkstra应用于该图形。 Assuming that the additional_data cost is always an integer, the transformation is: 假设additional_data cost总是一个整数,那么转换是:

  1. Take every original node n and create a set of nodes (n, c) for every integer value of c from 0 up to the value of the budget (the maximum sum of additional_data that you can tolerate) 获取每个原始节点n并为c的每个整数值创建一组节点(n,c),从0到预算值(您可以容忍的additional_data的最大总和)
  2. Take every original connection n1 -> n2 with weight w and additional_data a, and create a set of connections from every node (n1, c) to the node (n2, c+a), each with weight w 将每个原始连接n1 - > n2与权重w和additional_data a一起,并创建一组从每个节点(n1,c)到节点(n2,c + a)的连接,每个连接具有权重w

The nodes in the original graph model positions in space. 原始图模型中的节点位于空间中。 The nodes in the transformed graph model positions in a state space, where the state variables are position, and the amount of the budget spent so far. 变换后的图模型中的节点位于状态空间中,状态变量是位置,以及到目前为止所花费的预算金额。

If you want to get from A to Z with a budget of x, then you then simply use Dijkstra's algorithm to find a route from (A, 0) to one of the nodes (Z, c <= x). 如果你想要从预算为x的A到Z,那么你只需使用Dijkstra的算法来找到从(A,0)到其中一个节点(Z,c <= x)的路线。

EDIT : I have implemented the modified Dijkstra's algorithm: https://bitbucket.org/twic/roadsproblem . 编辑 :我已经实现了修改后的Dijkstra算法: https//bitbucket.org/twic/roadsproblem The crux of it is in src/solver.py . 它的症结在于src/solver.py

Here is an explanation of how the algorithm you have found will handle your example problem. 以下是您找到的算法如何处理示例问题的说明。

The problem is to find the shortest path between node one and node four with the extra condition that the accumulated cost along the way should not be more than 7 . 问题是找到node onenode four之间的最短路径, node one额外条件是沿途的累计成本不应超过7

The solution we want to find is to first go from node one to node node two , a distance of 190 and at a cost of 4 . 我们想要找到的解决方案是首先从node one到节点node two ,距离为190 ,成本为4 And then go from node two to node four using the path of distance 195 and cost 3 . 然后使用距离195和成本3的路径从node twonode four In total the path has a distance of 385 and a cost of 7 . 总的来说,路径的距离为385 ,成本为7

Step 1 第1步

So how does the algorithm find this? 那么算法怎么找到这个呢? The first step is to set up the matrix minArray(i,j) just like you have done. 第一步是像你一样设置矩阵minArray(i,j) The element (i,j) of the array holds the distance you must travel to get to node j with exactly i money remaining. 元素(i,j)阵列的持有你必须前往到达节点的距离j与正好i的钱剩下。

原始数组。

Starting out there are no visited elements and since we are starting at node one with 7 "monies" the top left element is set to zero. 开始时没有访问过的元素,因为我们从node one开始有7 “monies”,左上角的元素被设置为零。 The empty spaces in the table above correspond to values that are set to infinity in the array. 上表中的空白对应于在数组中设置为infinity值。

Step 2 第2步

Next, we find the lowest value of the array, this is the zero at position (remaining money, node) = (7,1) . 接下来,我们找到数组的最低值,这是位置的零(remaining money, node) = (7,1) This element is set to visited (the state of an element is kept track of using a matrix visitedArray of the same size as minArray ) which means that we have selected node one . 此元素被设置为visited (一个元件的状态被保持使用矩阵的轨道visitedArray相同大小的minArray ),这意味着我们选择了node one Now all nodes that connect to node one are updated with values by traversing the corresponding edges. 现在,通过遍历相应的边来更新连接到node one所有节点的值。

阵列一。

Here minArray(6,3) = 191 which means that we have gone a distance of 191 to get to node three and the money we have left is 6 since we have payed a cost of 1 to get there. 这里minArray(6,3) = 191 ,这意味着我们已经走了191到达minArray(6,3) = 191 node three ,而我们剩下的钱是6因为我们已经支付了11的成本。 In the same way minArray(3,2) is set to 190 . 同样, minArray(3,2)设置为190 The red square marks that element (7,1) is visited. 红色标记表示访问了元素(7,1)

Step 3 第3步

Now we again find the lowest unvisited element (which is minArray(3,2) = 190 ), set it to visited and update all elements that connect to it. 现在我们再次找到最低的未访问元素( minArray(3,2) = 190 ),将其设置为visited并更新连接到它的所有元素。 This means that the distance is accumulated and the remaining money is calculated by subtracting the cost from the current value. 这意味着累积距离并通过从当前值中减去成本来计算剩余资金。

数组二。

Note that it is too expensive to go back to node one from node two . 请注意,从node two返回node one太昂贵了。

Step 4 第四步

The next step, selecting minArray(6,3) = 191 looks like this. 下一步,选择minArray(6,3) = 191就像这样。

阵列三。

Step 5 第5步

Three steps later the array looks like this. 三步后,阵列看起来像这样。 Here the two elements that equal 382 and the one that equals 383 have been selected. 这里选择了两个等于382元素和一个等于383元素。 Note that the value of an element is only updated if it is an improvement of (ie lower than) the current value. 请注意,元素的值仅在它是当前值的改进(即低于)时才更新。

阵列四。

Step 6 第6步

The array continues to fill up until all elements are either visited or still have infinite value. 数组继续填满,直到所有元素都被访问或仍具有无限值。

数组5。

Final step 最后一步

The final step is to find the total distance by finding the lowest value of column four. 最后一步是通过找到第四列的最低值来找到总距离。 We can see that the minimal value, minArray(0,4) = 385 corresponds to the correct solution. 我们可以看到最小值minArray(0,4) = 385对应于正确的解。

Note: If all values of column four would have been infinite, it would mean that there is no valid solution. 注意:如果第四列的所有值都是无限的,则意味着没有有效的解决方案。 The algorithm also specifies that if there are multiple values of equal and minimal distance in column four, the cheapest one is selected. 该算法还指定如果在第四列中存在多个相等和最小距离的值,则选择最便宜的一个。

I do not think Dijkstra's algorithm is a good solution to this problem since the distance needed is not only the source node and destination. 我不认为Dijkstra的算法是解决这个问题的好方法,因为所需的距离不仅是源节点和目的地。 Here is a solution based upon A* search algorithm.\\ 这是一个基于A *搜索算法的解决方案。

First, perform a FolydWarshall based on weight and then based on additional_data to get the least weight and least additional_data for each node pair in the graph. 首先,执行基于FolydWarshall weight ,然后根据additional_data获得至少weight和至少additional_data为图表中的每个节点对。

  FloydWarshall(Weights);
  FloydWarshall(Additional_datas);

Second, we perform a A* search based on priority queue with element like following structure(Use c code as example.) The priority queue will automatically get the weights_sum least in all the candidates. 其次,我们基于优先级队列执行A *搜索,其元素如下面的结构(使用c代码作为示例。)优先级队列将自动获得所有候选中的weights_sum。 weights_expected is the best guess of the path through current node to destination node while weights_now is current weight 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);
    }

In A* search algorithm, 在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* search will be still NP hard since in worst case it has to search each possible path. A *搜索仍然是NP难度,因为在最坏的情况下,它必须搜索每个可能的路径。 However it will be much faster than a simple DFS search and perform lots of search path cuts. 然而,它将比简单的DFS搜索快得多,并执行大量的搜索路径切割。

You could make a copy of the node with 0 cost between them that adds the 2nd possible path. 您可以在节点之间创建一个0成本的副本,以添加第二个可能的路径。

Like so (pseudocode) 像这样(伪代码)

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

becomes this: 成为这个:

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

Not sure if this will work, but it's an idea. 不确定这是否有效,但这是一个想法。

The additional condition will break Dijkstra. 附加条件将打破Dijkstra。 Think of it like this: if you have a path A->B in a graph and an edge B->C in a graph, then the shortest path A->C that involves B is surely the minimum path of A->B->C. 可以这样想:如果图中的路径为A-> B,图中的边B-> C,那么涉及B的最短路径A-> C肯定是A-> B的最小路径 - >下进行。 In your case this condition doesn't hold, because while A->B and B->C might be valid, A->B->C might not be valid. 在您的情况下,此条件不成立,因为虽然A-> B和B-> C可能有效,但A-> B-> C可能无效。

Okay, this is the point where you grab a piece of paper and try this. 好的,这就是你拿一张纸然后试试的地方。

If you look at your graph, and assuming you want to go from (1) to (4), notice how you can eliminate (3) by introducing the following edges: 如果您查看图表,并假设您想从(1)到(4),请注意如何通过引入以下边缘来消除(3):

  • (1)->(4), [390, 2] (1) - >(4),[390,2]
  • (1)->(2), [383, 3] (1) - >(2),[383,3]
  • (2)->(4), [391, 3] (2) - >(4),[391,3]

Once you have eliminated the all edges but a straight line, the problem becomes somewhat easier: for each node you can keep track of how much [distance, additional] it will cost to reach the goal. 一旦消除了除了直线之外的所有边缘,问题就会变得容易一些:对于每个节点,您可以跟踪到达目标需要多少[距离,额外]。 You don't have to store additional > max or 'remaining additional' < 0, since that's not a viable solution. 您不必存储额外的> max或'剩余额外'<0,因为这不是一个可行的解决方案。 Also, if you have multiple distances for equal additional, only the minimal distance should be kept. 此外,如果您有多个等距离的距离,则只应保留最小距离。

The best solution is now the one with the minimal distance in the last node (or the first, depending on how you ordered it). 现在最好的解决方案是在最后一个节点中具有最小距离的解决方案(或者第一个,取决于您如何订购它)。 If down the road, you kept pointers on how you got there (eg if you update the value in the matrix also store the element that made it change), you can backtrack the path as well. 如果你在路上,你保持指向你如何到达那里(例如,如果更新矩阵中的值也存储使其更改的元素),您也可以回溯路径。

Here you should note that you can do the same when the problem was in the non-eliminated form with the matrix you suggest: x-axis as nodes, y-axis as 'list per node'. 在这里您应该注意,当问题处于非消除形式时,您可以使用您建议的矩阵:x轴作为节点,y轴作为“每个节点列表”。

That should do it. 应该这样做。

你可以使用bellman-ford算法,假设你的addittional-data是bellman-ford算法中的edges数参数

This problem is NP-complete. 这个问题是NP完全的。 No algorithm is more efficient than the one explained by multiple people (Tom Anderson, user1884905). 没有算法比多人解释的算法更有效(Tom Anderson,user1884905)。

Proof: By reducing of subset-sum for non-negative numbers. 证明:通过减少非负数的子集和。

Take an instance A of subset-sum (N numbers). 取一个子集和的实例A(N个数)。 Construct a graph, where there are N+1 nodes. 构造一个图形,其中有N + 1个节点。 For nodes i and i+1 , make 2 paths , one with weight=0, additional_data=A[i], another with weight=A[i], additional_data=0. 对于节点i和i + 1,制作2个路径,一个具有权重= 0,additional_data = A [i],另一个具有权重= A [i],additional_data = 0。 Choose x(the limit for sum of additional_data). 选择x(additional_data总和的限制)。

Observe that the algorithm must minimize sum of weights, so it will also maximize sum of additional_data. 观察到算法必须最小化权重之和,因此它还将最大化additional_data的总和。 So the paths of the first kind chosen will be the paths associated with numbers in the result of the subset-sum problem. 因此,所选择的第一种路径将是与子集和问题的结果中的数字相关联的路径。

Your additional condition makes the problem a lot harder. 你的附加条件使问题变得更加困难。 Looking at it, I think the only thing you can do, is find out all possible paths between the source and the target, sort them by total edge weight, and then check one by one if your additional condition holds. 看看它,我认为你能做的唯一事情就是找出源和目标之间的所有可能路径,按总边重量对它们进行排序,然后如果你的附加条件成立则逐个检查。

However, the problem of finding all possible paths between two vertices, is NP-Hard . 然而,找到两个顶点之间的所有可能路径的问题是NP-Hard A slightly modified version of DFS might be able to do the trick, but probably not in all cases. DFS的略微修改版本可能能够做到这一点,但可能并非在所有情况下都可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM