Algorithm for finding distinct paths from A to B in weighted, directed, cyclic graph - algorithm

Suppose we have a DIRECTED, WEIGHTED and CYCLIC graph.
Suppose we are only interested in paths with a total weight of less than MAX_WEIGHT
What is the most appropriate (or any) algorithm to find the number of distinct paths between two nodes A and B that have a total weight of less than MAX_WEIGHT?
P.S: It's not my homework. Just personal, non-commercial project.

If the number of nodes and MAX_WEIGHT aren't too large (and all weights are integers), you can use dynamic programming
unsigned long long int num_of_paths[MAX_WEIGHT+1][num_nodes];
initialize to 0, except num_of_paths[0][start] = 1;.
for(w = 0; w < MAX_WEIGHT; ++w){
for(n = 0; n < num_nodes; ++n){
if (num_of_paths[w][n] > 0){
/* for each child c of node n
* if w + weight(n->c) <= MAX_WEIGHT
* num_of_paths[w+weight(n->c)][c] += num_of_paths[w][n];
*/
}
}
}
solution is sum of num_of_paths[w][target], 0 <= w <= MAX_WEIGHT .

Simple recursion. You have it in exponential time. Obviously, no zero-weight cycles allowed.
function noe(node N, limit weight W)
no. of path is zero if all outgoing edges have weight > W
otherwise no. of path is sum of numbers of path obtained by sum(noe(C1,W-W1),noe(C2,W-W2),... noe(Cn,W-Wn)) where C1 ... Cn are the nodes connected to N for which W-Wi is not negative where Wi is weight of the connecting edge, written in your favorite language.
More eficient solution should exist, along the lines of Dijkstra's algorithm, but I think this is enough for homework.

Your problem is more general case of K-Disjoint Path In directed planar graphs, with not fixed K.
K disjoint paths problem for directed planar graphs is as this:
given: a directed planar graph G = (V;E) and k pairs (r1; s1); .... ; (rk; sk) of vertices of G;
find: k pairwise vertex-disjoint directed paths P1; ... ; Pk in G, where Pi runs from ri to si (i = 1; .... ; k).
In k-disjoint path you can draw arc from all si to B, and Also arc from A to all ri by this way you create graph G' from G.
Now if you can solve your problem in G' in P you can solve k-disjoint Path in G, So P=NP.
But if you read the paper linked it gives some idea for general graph (solving k-disjoint path with fixed k) and you can use it to have some good approximation.
Also there is more complicated algorithm which solves this problem in P (for fixed k) in general graphs. but in all it's not easy (it's by Seymour ).
So your best choice currently is to use brute force algorithms.
Edit: Because MAXWEIGHT is independent to your input size (your graph size) It doesn't affect to this problem, Also because it's NP-Hard for undirected unweighted graph, still you simply can conclude it's NP-Hard.

Related

Find path with maximum cost difference of edges in directed graph in linear-time

Having a directed graph G with edges having positive weights, we define the cost of a path the difference between the edge with minimum weight and maximum weight. The goal is to find a path with maximum cost among other paths. We don't need to return the path itself just the maximum cost.
If x is the number of vertices and y is the number of edges then x < 10^5 and y < min(x^2,10^5). The time limit is 1 second.
Based on the bounds I think this problem has to be solved in O(x+y) time.
So based on the problems properties ans some studying of other algorithms I thought that on possible answer may contain multiple DFS's (like the SCC problem). I also find a similar problem with Dijkstra's algorithm that can be modified for this problem but I'm not very sure that the complexity would be OK. Also there are some other questions similar to mine however the answers were of O(m^2) or higher which were not very efficient.
Other than what was mentioned above I have no idea to solve the problem and some insight would be very helpful. Thanks
Solution:
Due to the fact that our graph can have cycles, this complicates things for us. Let's build a new graph in which we "compress" all the components of a strong connection into a single vertex, so new graph will be acyclic. During this process let's memorize maximum(maximumWeight[v]) and minimum(minimumWeigh[v]) weights of the edges for each strongly connected components.
We spent O(|V| + |E|) time for it, where |V| is count of vertexes and |E| is count if edges.
After that let's make a topological sorting of given graph in O(|V|+|E|) time complexity. Then let's calculate simple DP.
dpMax[v] - the maximum weight of the edge to which there is a path from this vertex.
dpMin[v] - the minimum weight of the edge to which there is a path from this vertex.
Default value:
If vertex v is strongly connected component, then maximum and minimum weights already calculates in maximumWeight[v] and minimumWeigh[v], so dpMax[v] = maximumWeight[v] and dpMin[v] = minimumWeight[v].
Otherwise maximumWeight[v] = -Infinity and minimumWeigh[v] = Infinity.
In topological order let's improve our DP for each vertex:
int answer = -Infinity;
for(auto v : vertexesInTopologicalOrder) {
int newMinDp = dpMin[v], newMaxDp = dpMax[v];
for(auto e : v.outgoingEdges) {
int l = dpMin[v];
int r = dpMax[v];
l = min(l, e.weight);
r = max(r, e.weight);
l = min(l, dpMin[e.target]);
r = max(r, dpMax[e.target]);
answer = max(answer, e.weight - l);
answer = max(answer, r - e.weight);
newMinDp = min(newMinDp, l);
newMaxDp = max(newMaxDp, r);
}
dpMin[v] = newMinDp;
dpMax[v] = newMaxDp;
}
Since we calculating DP in topological order, the DP at achievable vertexes have already been calculated.
For a better understanding, let's look at an example.
Let's say we have such an initial graph.
After compression, the graph will look something like this.
After topological sorting, we get this order of vertices. (Green numbers)
Sequentially calculate all DP values, along with updating the answer.
Final answer 6 will be achieved during calculating top vertex DP.
I hope it turned out to be quite detailed and clear. Final time complexity is O(|V|+|E|).

Disconnect all vertices in a graph - Algorithm

I am looking for an algorithm that finds minimal subset of vertices such that by removing this subset (and edges connecting these vertices) from graph all other vertices become unconnected (i.e. the graph won't have any edges).
Is there such algorithm?
If not: Could you recommend some kind of heuristics to designate the vertices.
I have a basic knowledge of graph theory so please excuse any incorrectness.
IIUC, this is the classic Minimum Vertex Cover problem, which is, unfortunately, NP Complete.
Fortunately, the most intuitive and greedy possible algorithm is as good as it gets in this case.
The greedy algorithm is a 2-approximation for vertex cover, which in theory, under the Unique Games Conjecture, is as good as it gets. In practice, solving a formulation of vertex cover as an integer program will most likely yield much better results. The program is
min sum_{v in V} x(v)
s.t.
forall {u, v} in E, x(u) + x(v) >= 1
forall v in V, x(v) in {0, 1}.
Try this way:
Define a variable to count number of vertexes, starting by 0;
Create a Max-Heap of vertexes sorted by the length of the adjacent list of each vertex;
Remove all edges from the first vertex of the Heap (the one with biggest number of edges) and remove it from the Heap, adding 1 to the count;
Reorder the Heap now that number of edges of the vertexes changed, repeating the previous step until the length of the adjacent list from the first vertex is 0;
Heap Q
int count = 0
while(1){
Q = Create_Heap(G)
Vertex first = Q.pop
if(first.adjacents.size() == 0) {
break
}
for( Vertex v : first.adjacent ){
RemoveEdge(first, v)
RemoveEdge(v, first) /* depends on the implementation */
}
count = count + 1
}
return count

Finding all shortest paths from source to all vertices in a digraph

We are given a directed graph G (possibly with cycles) with positive edge weights, and the minimum distance D[v] to every vertex v from a source s is also given (D is an array this way).
The problem is to find the array N[v] = number of paths of length D[v] from s to v,
in linear time.
Now this is a homework problem that I've been struggling with for quite long. I was working along the following thought : I'm trying to remove the cycles by suitably choosing an acyclic subgraph of G, and then try to find shortest paths from s to v in the subgraph.
But I cannot figure out explicitly what to do, so I'd appreciate any help, as in a qualitative idea on what to do.
You can use dynamic programming approach in here, and fill up the number of paths as you go, if D[u] + w(u,v) = D[v], something like:
N = [0,...,0]
N[s] = 1 //empty path
For each vertex v, in *ascending* order of `D[v]`:
for each edge (u,v) such that D[u] < D[v]:
if D[u] + w(u,v) = D[v]: //just found new shortest paths, using (u,v)!
N[v] += N[u]
Complexity is O(VlogV + E), assuming the graph is not sparsed, O(E) is dominanting.
Explanation:
If there is a shortest path v0->v1->...->v_(k-1)->v_k from v0 to v_k, then v0->...->v_(k-1) is a shortest path from v0 to v_k-1, thus - when iterating v_k - N[v_(k-1)] was already computed fully (remember, all edges have positive weights, and D[V_k-1] < D[v_k], and we are iterating by increasing value of D[v]).
Therefor, the path v0->...->v_(k-1) is counted in the number N[V_(k-1)] at this point.
Since v0->...->v_(k-1)-v_k is a shortest path - it means D[v_(k-1)] + w(v_k-1,v_k) = D[v_k] - thus the condition will hold, and we will add the count of this path to N[v_k].
Note that the proof for this algorithm will basically be induction that will follow the guidelines from this explanation more formally.

Path finding algorithm on graph considering both nodes and edges

I have an undirected graph. For now, assume that the graph is complete. Each node has a certain value associated with it. All edges have a positive weight.
I want to find a path between any 2 given nodes such that the sum of the values associated with the path nodes is maximum while at the same time the path length is within a given threshold value.
The solution should be "global", meaning that the path obtained should be optimal among all possible paths. I tried a linear programming approach but am not able to formulate it correctly.
Any suggestions or a different method of solving would be of great help.
Thanks!
If you looking for an algorithm in general graph, your problem is NP-Complete, Assume path length threshold is n-1, and each vertex has value 1, If you find the solution for your problem, you can say given graph has Hamiltonian path or not. In fact If your maximized vertex size path has value n, then you have a Hamiltonian path. I think you can use something like Held-Karp relaxation, for finding good solution.
This might not be perfect, but if the threshold value (T) is small enough, there's a simple algorithm that runs in O(n^3 T^2). It's a small modification of Floyd-Warshall.
d = int array with size n x n x (T + 1)
initialize all d[i][j][k] to -infty
for i in nodes:
d[i][i][0] = value[i]
for e:(u, v) in edges:
d[u][v][w(e)] = value[u] + value[v]
for t in 1 .. T
for k in nodes:
for t' in 1..t-1:
for i in nodes:
for j in nodes:
d[i][j][t] = max(d[i][j][t],
d[i][k][t'] + d[k][j][t-t'] - value[k])
The result is the pair (i, j) with the maximum d[i][j][t] for all t in 0..T
EDIT: this assumes that the paths are allowed to be not simple, they can contain cycles.
EDIT2: This also assumes that if a node appears more than once in a path, it will be counted more than once. This is apparently not what OP wanted!
Integer program (this may be a good idea or maybe not):
For each vertex v, let xv be 1 if vertex v is visited and 0 otherwise. For each arc a, let ya be the number of times arc a is used. Let s be the source and t be the destination. The objective is
maximize ∑v value(v) xv .
The constraints are
∑a value(a) ya ≤ threshold
∀v, ∑a has head v ya - ∑a has tail v ya = {-1 if v = s; 1 if v = t; 0 otherwise (conserve flow)
∀v ≠ x, xv ≤ ∑a has head v ya (must enter a vertex to visit)
∀v, xv ≤ 1 (visit each vertex at most once)
∀v ∉ {s, t}, ∀cuts S that separate vertex v from {s, t}, xv ≤ ∑a such that tail(a) ∉ S &wedge; head(a) &in; S ya (benefit only from vertices not on isolated loops).
To solve, do branch and bound with the relaxation values. Unfortunately, the last group of constraints are exponential in number, so when you're solving the relaxed dual, you'll need to generate columns. Typically for connectivity problems, this means using a min-cut algorithm repeatedly to find a cut worth enforcing. Good luck!
If you just add the weight of a node to the weights of its outgoing edges you can forget about the node weights. Then you can use any of the standard algorigthms for the shortest path problem.

Shortest path with a fixed number of edges

Find the shortest path through a graph in efficient time, with the additional constraint that the path must contain exactly n nodes.
We have a directed, weighted graph. It may, or may not contain a loop. We can easily find the shortest path using Dijkstra's algorithm, but Dijkstra's makes no guarantee about the number of edges.
The best we could come up with was to keep a list of the best n paths to a node, but this uses a huge amount of memory over vanilla Dijkstra's.
It is a simple dynamic programming algorithm.
Let us assume that we want to go from vertex x to vertex y.
Make a table D[.,.], where D[v,k] is the cost of the shortest path of length k from the starting vertex x to the vertex v.
Initially D[x,1] = 0. Set D[v,1] = infinity for all v != x.
For k=2 to n:
D[v,k] = min_u D[u,k-1] + wt(u,v), where we assume that wt(u,v) is infinite for missing edges.
P[v,k] = the u that gave us the above minimum.
The length of the shortest path will then be stored in D[y,n].
If we have a graph with fewer edges (sparse graph), we can do this efficiently by only searching over the u that v is connected to. This can be done optimally with an array of adjacency lists.
To recover the shortest path:
Path = empty list
v = y
For k= n downto 1:
Path.append(v)
v = P[v,k]
Path.append(x)
Path.reverse()
The last node is y. The node before that is P[y,n]. We can keep following backwards, and we will eventually arrive at P[v,2] = x for some v.
The alternative that comes to my mind is a depth first search (as opposed to Dijkstra's breadth first search), modified as follows:
stop "depth"-ing if the required vertex count is exceeded
record the shortest found (thus far) path having the correct number of nodes.
Run time may be abysmal, but it should come up with the correct result while using a very reasonable amount of memory.
Interesting problem. Did you discuss using a heuristic graph search (such as A*), adding a penalty for going over or under the node count? This may or may not be admissible, but if it did work, it may be more efficient than keeping a list of all the potential paths.
In fact, you may be able to use backtracking to limit the amount of memory being used for the Dijkstra variation you discussed.
A rough idea of an algorithm:
Let A be the start node, and let S be a set of nodes (plus a path). The invariant is that at the end of step n, S will all nodes that are exactly n steps from A and the paths will be the shortest paths of that length. When n is 0, that set is {A (empty path)}. Given such a set at step n - 1, you get to step n by starting with an empty set S1 and
for each (node X, path P) in S
for each edge E from X to Y in S,
If Y is not in S1, add (Y, P + Y) to S1
If (Y, P1) is in S1, set the path to the shorter of P1 and P + Y
There are only n steps, and each step should take less than max(N, E), which makes the
entire algorithm O(n^3) for a dense graph and O(n^2) for a sparse graph.
This algorith was taken from looking at Dijkstra's, although it is a different algorithm.
let say we want shortest distance from node x to y of k step
simple dp solution would be
A[k][x][y] = min over { A[1][i][k] + A[t-1][k][y] }
k varies from 0 to n-1
A[1][i][j] = r[i][j]; p[1][i][j]=j;
for(t=2; t<=n; t++)
for(i=0; i<n; i++) for(j=0; j<n; j++)
{
A[t][i][j]=BG; p[t][i][j]=-1;
for(k=0; k<n; k++) if(A[1][i][k]<BG && A[t-1][k][j]<BG)
if(A[1][i][k]+A[t-1][k][j] < A[t][i][j])
{
A[t][i][j] = A[1][i][k]+A[t-1][k][j];
p[t][i][j] = k;
}
}
trace back the path
void output(int a, int b, int t)
{
while(t)
{
cout<<a<<" ";
a = p[t][a][b];
t--;
}
cout<<b<<endl;
}

Resources