Get path in graph with weighted vertices and edges - ruby

If i have the following undirected graph with weighted vertices and edges:
I am trying to come up with a ruby algorithm to find a best shortest path within a defined limit (sum of edges) with the highest value (sum of vertices).
The start point will also be the ending point.
for e.g. finding a path with a maximum of 20 with the highest total value.
This problem seems like a np hard problem and it is hard to find the best solution.
Is there a modified algorithm of dijkstra? I tried using a greedy algorithm but it did not give me a optimal solution. and by using bruteforce on all poosible path will work, but it will take very long if the number of nodes increases.
Was wondering if there is any combination of algorithms that i can use to improve my solution?
Thanks.

You can find an example of Djikstra's algorithm here. What I would do is add a variable to count the number of vertices in the shortest path, and evaluate if the shortest path has too many vertices or is too long once determining what the shortest path even is.

The problem is actually NP hard, you can prove this doing a reduction of Hamiltonian path problem to this problem. Basically given an input for the Hamiltonian path problem (we can stay with the undirected graph) you can create an input for the problem you describe if follow this steps:
build a new graph
create a new graph that is the same that receive the Hamiltonian path problem but give to each vertex and edge weight 1.
create an input for your problem
Pass to your problem the graph just created in the previous step and limit equals to infinity.
Notice now that the result given by your problem is a path as longest as posible with respect at the number of vertex, since the limit restriction is an upper bound in the sum of weight of the edges. This mean that you can add as vertex as posible and still complaint the limit restriction.
How many vertex are in the path determine the total value of this (count of vertex in the path) since the weight is 1 for all of them. So the resulting path is the longest posible in the graph. With this insight we can verify if this path is a hamiltonian path, just check the length of the path. If the path is of length N where N is the number of nodes in the graph there is a hamiltonian path otherwise there isn't.
To solve the problem you can use an approach similar to Bellman-Ford with some modifications. First create a matrix A[i, j] where you storage all the highest total value paths that ends with j and has length (number of edges) i. This is the key, you can't just storage one of this path, because in the next step you need to check all of them to make a relax, here is where the implementation become non-polynomial. The relax technique in the step i iterate through all the storage path in A[i-1, u] and try to improve the value in A[i, v] saving the new paths that actually do it (you must check for >= when try to improve A[i, v] in order to get all the paths), of course this relax take into account the limit restriction. If you uses a global max and a global path and update it in each relax process, you end with the highest value path for the entire graph.

Related

Shortest path on graph with changing weights

I was trying to solve a local programming contest question. The problem is basically about finding the shortest path in a weighted graph. I am pretty new to these types of problems and I thought I could use Dijkstra's algorithm. However, there is a small complication - certain values are different, depending on the situation of this current path.
Problem
There are two types of weights: normal weights and weights with condition (let's call them K). The condition is this: once you move through edge with weight K, all other weights of type K have value of 0. This brings a few more problems, because the apparent shortest path can be beaten by a combination of edges with weights of type K.
Example
Below is this type of problem. If no weights would change their value, we could find the shortest path easily with Dijkstra. However, when weights K change their value, we can find a shorter path, because the weight of the edge C-D is 0 after moving through the edge A-C.
Question
How can I find the shortest path?
Can I use Dijkstra's algorithm here or is it better to use another algorithm like A* or BFS?
How many K's are there?
I it's only one, Dijkstra is good.
I will add to say that BFS does not handle weighs well.
Reminder: Dijkstra finds the shortest path from a vertex to all vertexes.
Run Dijkstra twice and define a different wight function for each run. First the wight function for K values is infinite. Second wight function for K values is 0.
Than compare the result from run1 to run2+K.
This is true because if the shortest path is without K first run will find it. otherwise it's with K and the second run will find it. Either way the algorithm will find it.

Given a weighted undirected graph, how do I find a path which has the total weights close to a given value?

Suppose I have a weighted, undirected graph. Each edge has a positive weight. I would like to find a simple path (no vertices appear in the path twice) from a given source node (s) to a target node (t) which has the total sum of weights close to a given value (P).
Even though it sounds like a well-studied problem, I couldn't find a satisfying solution. Many graph algorithms are aiming to find the shortest path (in a sense of steps or cost), but not to find the "matched" cost path.
A naive solution would be finding all paths from s to t, compute sum of weights for each path and select the one that is close to P. However, finding all paths between two nodes in a graph is known to be #P-hard.
A possible solution could be modified the A* algorithm, so that for each node in the frontier we get the cost from the root to that node (g), and estimate the cost from that node to the goal (h). Then instead of choosing a node with the smallest g+h, we choose a node with the smallest |P - (g+h)|. However, I am not sure if this is the best solution.
Another thought is inspired from the linear programming since the objective function of this problem is sum(weights of a path from s to t) - P = 0. I know the shortest path problem can be formed as a linear programming task but not sure how to formulate this problem as a one.
Please help, thanks in advance!
This problem is NP-hard via a reduction from the Hamiltonian path problem. In that problem, you are given a graph and a pair of nodes s and t and are asked whether there's a simple path from s to t that passes through all the nodes in the graph. You can solve the Hamiltonian path problem via your problem as follows:
Assign each edge in the graph weight 1.
Find the s-t simple path whose weight is as close to n-1 as possible, where n is the number of nodes in the graph.
Returns whether this path has cost exactly n-1.
If the graph has a Hamiltonian path, then that path will have cost n-1. Otherwise, it doesn't, and the best path found will have a cost that's lower than n-1.

Finding Shortest path in weighted directional multigraph with extra constraints

Given a weighted directed multigraph, I have to find shortest path between starting vertex u to vertex v. Apart from weight, each edge also has time. The path connecting u and v cannot take more than a given maximum time. The trouble is while using Djikstra, there are chances that shortest path takes more time than the limit.
My approach is to find all valid paths between u and v and than minimize the weight. But the approach is not practical due to its high complexity.
Any ideas?
If weights are small enough
In this case, what you can do is for each node, store all possible sums of weights that you can get on path to that node. Now you can do dijsktra on this new graph and try to minimize time over nodes which are pairs (node, weight_sum).
If times are small enough
You can do the same as in previous example, but over pairs (node, time).
General problem
I'm afraid that in general all you can do is try all possible paths, try to improve it with prunning.

How to find ALL Eulerian paths in directed graph

I have a directed graph and I want to find all existing eulerian paths (in my graph I actually know that those will be circuits).
I have done some research so I can use for example Hierholzer's algorithm as in here: http://stones333.blogspot.co.uk/2013/11/find-eulerian-path-in-directed-graph.html to find a path from given node but this algorithm returns only one path I believe.
My idea to solve this is to have an algorithm that will return ALL existing Eulerian paths / circuits starting from given node. Then I will run this algorithms for all nodes and get the results. This will have n^2 or n^3 complexity which is great.
So my question is if there is an algorithm that will find all Eulerian paths / circuits in directed graph from given node? Or maybe someone knows another solution to my problem.
EDIT:
after Gassa comment I think that the solution with Euler paths might be an overkill for my problem. Problem is as follows: for given n we create a pairs of integers which sum is <= n. For those pairs find all paths that connects all of the pairs such that second value of previous pair equals to the first value from next pair (like domino).
Example: n = 2, then available pairs = {(0,0), (0,1),(1,0),(1,1),(2,0),(0,2)}. One of the valid chains = (0,0)=>(0,1)=>(1,1)=> (1,0)=>(0,2)=>(2,0). I preferred algorithm using graphs because for example (0,0) might not be valid sometimes, but let's say it is valid for the sake of this question. Brute force solution to this problem is to of course create all permutations of available pairs and then see if they are valid but this is obviously O(n!) complex. I am pretty sure this could be done in some "smart" way.
In the general case, the number of distinct Eulerian paths is exponential in the number of vertices n. Just counting the number of Eulerian circuits in an undirected graph is proven to be #P-complete (see Note on Counting Eulerian Circuits by Graham R. Brightwell and Peter Winkler). Quoting Wikipedia:
A polynomial-time algorithm for solving a #P-complete problem, if it
existed, would imply P = NP, and thus P = PH. No such algorithm is
currently known.
So perhaps you will need another approach.
If however your graph has certain properties which make the exponential number of Eulerian circuits impossible, do tell us these properties.
If you want to enumerate all Eulerian paths (and, like Gassa, I have my doubts), then the following simple output-sensitive algorithm has polynomial overhead, which, since n will be very small, should suffice. There's a recursive procedure for enumerating all paths from v that goes like this in Python.
def paths(v, neighbors, path): # call initially with path=[]
yield path[:] # return a copy of the mutable list
for w in list(neighbors[v]):
neighbors[v].remove(w) # remove the edge from the graph
path.append((v, w)) # add the edge to the path
yield from paths(w, neighbors, path) # recursively enumerate
# all path extensions from w
# in the residual graph
path.pop() # remove the edge from the path
neighbors[v].add(w) # add the edge to the graph
To return Eulerian paths only, we make two modifications. First, we prune the recursion if there is no Eulerian path extending the current path. Second, we do the first yield only when neighbors[v] is empty, i.e., the only extension is the trivial one, so path is Eulerian. Since the degree balance condition is satisfied, we prune by just checking strong connectivity of the non-isolated vertices at each recursive call, given that we add an arc from the starting vertex to v. This can be accomplished with two traversals, one to verify that every non-isolated vertex can reach the starting vertex and one to verify that every non-isolated vertex is reachable from v. (Alternatively, you could add the arc temporarily and do one traversal, but then you'd have to handle multigraphs, which you may not want to.)

finding whether a path of a specific length exists in an acyclic graph

In an acyclic graph, I am trying to find out whether or not a path of length L exists between two given nodes. My questions is, what is the best and the simplest Algorithm to use in this case.
Note that the graph has a maximum of 50 nodes and 100 edges.
I have tried to find all the paths using DFS and then to check if that path exists between the two nodes but I got the answer "Time Limit Exceeded" from the online judge.
I also used the Uniform Cost Search Algorithm but I also a got a negative response.
I need a more efficient way for solving such problem. Thank you.
I don't know if it will be faster then a DFS approach - but it will give a feasible solution:
Represent the graph as a matrix A, and calculate A^L - a path of length L between i and j exists if and only if A[i][j] != 0
Also, regarding DFS solution: You do not need to find all paths in the DFS - you should limit yourself to paths of length <= L, and by this trim some searches, once the length have exceeded the needed length. You could also escape the search once a path of length L is reaching the target.
Another possible optimization could be bi-directional search.
Find all vertices which have path of length L/2 from the source to
them.
Next, find all vertices which have paths of length L/2 from them
to the target (DFS on the reverse graph)
Then, check if there is a vertex that is common to both sets, if
there is - you got a path of length L from the source to the target.
Since the graph is acyclic you can order vertices topologicaly.
Let's name starting vertex A and finish vertex B.
Now the core algorithm starts:
For each vertex count all possible distances from A to this vertex. At start there is
one path from A to A with length zero.
Then take vertices in topological order.
When you pick vertex x: Look at each predecessor and update possible distances here.
This should run in O(N^3) time.
You can use a modified Dijkstra algorithm where instead of saving for every vertex the minimum distance to the origin, you save all the possible distances less or equal to the one desired.
I believe that you can use the following algorithm to find the longest path in a tree. This assumes that your graph is connected, if it is not you would need to rerun this on each connected component:
Pick an arbitrary node, A.
Do a BFS (or DFS) from A to find the node in the tree farthest from A, call this node B.
Do a BFS (or DFS) from B to find the node in the tree farthest from B, call this node C.
The path from B to C is the longest path in the tree (possibly tied for longest).
Obviously if this path is longer than L then you can shorten it to find a path of length L.

Resources