问题
I have n
vertices and m
undirected weighted edges between them (weights are representing minutes). Each vertex contains a number of minutes required to drink a coffee on that vertex.
I want to determine the shortest amount of time (minutes) neccessary to get from vertex v
to vertex w
but with the additional constraint that I have to drink my coffee on exactly one of the vertices on my way from v
to w
).
Example:
(number in the vertex is the amount of minutes required to drink a coffee, the weights on the edges represent the amount of minutes neccessary to travel this edge)
Get from v
to w
and drink a coffe on your way, output the minimal neccessary time (output should be 30).
My current approach is to find the shortest path with Dijkstra (sum up the weights of all edges on that path) and then add the value of the vertex with the lowest coffee time on that path to my result in order to get the total amount of time neccessary to get from v
to w
.
My approach doesn't work, here is an example where my approach fails (the result of my approach is 12 minutes, the actual result should be 6 minutes) :
How to determine the shortest amount of time from vertex v
to w
with the constraint that I need to drink a coffe on my path?
回答1:
The standard way to solve this problem is:
make 2 copies of your graph -- the
need_coffee
version and thehad_coffee version
.Connect each
need_coffee
node with the correspondinghad_coffee
node, with an edge cost equal to the cost of drinking coffee at that node.Use Dijkstra's algorithm to find the shortest path from
V_need_coffee
toW_had_coffee
回答2:
One way to do it is as following:
- Compute the shortest path from u to all the other vertices and call it p(u,x)
- Compute the shortest path from all the vertices to v and call it p(x,v)
- loop over all vertices and find the minimum of the value (p(u,x)+coffee(x)+p(x,v))
Doing so will lead to an algorithm with the same time complexity than Dijkstra's one (if you use Dijkstra's algorithm in step 1 and 2)
回答3:
I would try to write an A* algorithm to solve this. When you expand a node, you will get two children for every outgoing vertex; one where you drink the coffee and one where you don't. If you precondition your algorithm with a run of Dijkstra's (so you already have precomputed shortest paths), then you could inform the A* search's heuristic with the Dijkstra's shortest path + minimum time to drink a coffee (or + 0 if coffee already drunk).
The A* search terminates (you've reached your goal) when you have not only arrived at the destination node, but also have drank your coffee.
Example search for second scenario:
Want: A --> C
A(10) -- 1 -- B(10) -- 1 -- C(10)
\ /
\ /
2 -------- D(2) ------- 2
Expand A
A*(cost so far: 10, heuristic: 2) total est cost: 12
B (cost so far: 1, heuristic: 1 + 2) total est cost: 3
B*(cost so far: 11, heuristic: 1) total est cost: 12
D (cost so far: 2, heuristic: 2 + 2) total est cost: 6
D*(cost so far: 14, heuristic: 2) total est cost: 16
Expand B
A*(cost so far: 12, heuristic: 2) total est cost: 14
B*(cost so far: 11, heuristic: 1) total est cost: 12
C(cost so far: 2, heuristic: 2) total est cost: 4
C*(cost so far: 12, heuristic: 0) total est cost: 12
Expand C
B*(cost so far: 13, heuristic: 1) total est cost: 14
C*(cost so far: 12, heuristic: 0) total est cost: 12
Expand D
A* (cost so far: 14, heuristic: 2) total est cost: 16
D* (cost so far: 4, heuristic: 2) total est cost: 6
C (cost so far: 4, heuristic: 0 + 2) total est cost: 6
C* (cost so far: 6, heuristic: 0) total est cost: 6
Expand C*
goal reached. total cost: 6
Key:
* = Coffee from parent was drunk
So you can see that what this algorithm will do is first try to go down Dijkstra's shortest path (never drinking the coffee). And then when it reaches the end it will see a physical goal state, but with a need to still drink a coffee. When it expands this physical goal state to drink coffee, it will see that the cost to arrive is suboptimal, so it continues its search from another branch and proceeds.
Note that in the above, A and A* are different nodes, so in some way you can revisit a parent node (but only if the coffee drinking state is different). This is to address a graph like this:
Want A-->B
A(20) -- 1 -- B(20)
\
2
\
C(1)
Where it would make sense to go from A->C->C*->A*->B*
I'm not sure yet if we need to distinguish "coffee drank" states by which node we drank the coffee at, but I'm leaning towards no.
来源:https://stackoverflow.com/questions/44133138/shortest-path-with-a-twist