2
votes

I am trying to solve a SSSP problem in a connected directed weighted cyclic graph with non-negative weights. The catch here is, this problem asks for the SSSP that uses at most k vertices.

I tried using modified dijkstra's algorithm to solve this problem, keeping a 3-tuple in my priority queue. i.e. (vertex weight, number of vertices in path to this vertex (inclusive), vertex index). My algorithm prevents nodes that are more than k vertices away from being pushed into the priority queue and thus being considered in the shortest path.

Somehow, my algorithm is getting the wrong answer. One reason is, if an initially smaller weighted edge leads to a non-valid path and a initially larger weighted edge leads to a valid path, then my algorithm (being greedy) will report that it cannot find a valid path to the destination.

Edit: Solution code redacted as it is not helpful.

2

2 Answers

1
votes

I've found it hard to read your code - so maybe you're already doing this: give each vertex a collection of best paths (edit: actually each vertex stores only the previous step of each of the possible paths), storing the least expensive for that number of visited vertices, once a path goes over the maximum vertex count you can discard it, but you can't discard a more expensive (in terms of total edge lengths) path until you know that the cheaper paths will eventually reach the target in an acceptable number of vertices. At the end you may have more than one complete path, and you just choose the least edge-wise expensive regardless of its number of vertices (you'd have already discarded it if there were too many)

(Your code would be easier to read if you create a class/struct for some of the things you're storing as pairs of pairs etc, then you can give the members clearer names than second.first etc. Even if you are OK with the current naming, the extra clarity may help you get some other answers if the above hasn't helped.)

Edit to answer: "How do I keep the more expensive path until I know that the cheaper path will lead to a solution? "

Your priority queue is nearly doing this already - its not that each vertex (n) has a complete path stored as I originally implied, currently you just store the best previous vertex (n-1) to use to get to vertex n - and its cost and its vertex count. I'm saying that instead of storing that one best choice for vertex n-1 you store several options, e.g. the best route to A using 3 previous vertices is from vertex B and costs 12, and the best route using 4 is from vertex C and costs 10. (In all the above best means best found so far in the search)

You only need to store the cheapest route for a given number of vertices. You keep a route if (but only if) its better on either the cost or the vertex count.

In my above example you need to keep both because the cheaper route to this vertex uses more previous vertices so might result in too many vertices before reaching the target - its not clear at that stage which path will be best in the end.

So you need to change your collection type, and your rule for discarding options. You could for example use a std::map where previous vertices count is the key and total edge cost and previous vertex ID are stored in the value, or an array of total costs where index is the count.

0
votes

I think you want to store two incrementors with each node: one for the node count and one for the weighted distance. You use the node-count as an early terminator to discard those paths from the set of potential options. You use the weighted distance to choose the next node to iterate, and discard based on node count. In this way, if you fully terminate all the nodes on the periphery as discardable, then you know there's no eligible path to the destination that's at most the required number of hops. If you get to the destination within your list of periphery nodes, then you automatically know it's not more than the restricted number of nodes, and by induction you know it's already the shortest way of getting there, because every other path that could be found from then on must already have a longer path.