Linear time Graph algorithm - algorithm

Given an undirected graphG = (V,E), is there an algorithm that computes the total number of shortest path between two arbitrary vertices u & v ? I think we can make use of the Dijkstra's algorithm.

Yes you can use dijkstra. Create an array that store total number of shortest path to any node. Call it total. Initial value of all array member is 0 except total[s] = 1 where s is source.
In dijkstra loop, when comparing smallest path of a node, if the result of comparation is smaller, update the total array of that node with the number of total of current node. if it equals, add the total array of that node with the number of total of current node.
Pseudocode taken from wikipedia with some modification:
function Dijkstra(Graph, source):
create vertex set Q
for each vertex v in Graph: // Initialization
dist[v] ← INFINITY // Unknown distance from source to v
total[v] ← 0 // total number of shortest path
add v to Q // All nodes initially in Q (unvisited nodes)
dist[source] ← 0 // Distance from source to source
total[source] ← 1 // total number of shortest path of source is set to 1
while Q is not empty:
u ← vertex in Q with min dist[u] // Source node will be selected first
remove u from Q
for each neighbor v of u: // where v is still in Q.
alt ← dist[u] + length(u, v)
if alt < dist[v]: // A shorter path to v has been found
dist[v] ← alt
total[v] ← total[u] // update the total array of that node with the number of total array of current node
elseif alt = dist[v]
total[v] ← total[v] + total[u] // add the total array of that node with the number of total array of current node
return dist[], total[]

Related

How can I find shortest path with maximum number of yellow edges

In given directed graph G=(V,E) , and weight function: w: E -> ℝ+ , such any vertex with color yellow or black, and vertex s.
How can I find shortest path with maximum number of yellow edges?
I thought to use Dijkstra algorithm and change the value of the yellow edges (by epsilon).. But I do not see how it is going to work ..
You can use the Dijkstra shortest path algorithm, but add a new vector Y that has an element for each node that keeps track of the number of the yellow edges that it took so far until we get to that node.
Initially, set Y[i] = 0 for each node i.
Also suppose Yellow(u,v) is a function that returns 1 if (u,v) is yellow and 0 otherwise.
Normally, in the Dijkstra algorithm you have:
for each neighbor v of u still in Q:
alt ← dist[u] + Graph.Edges(u, v)
if alt < dist[v]:
dist[v] ← alt
prev[v] ← u
You can now change this to:
for each neighbor v of u still in Q:
alt ← dist[u] + Graph.Edges(u, v)
if alt < dist[v]:
dist[v] ← alt
prev[v] ← u
Y[v]← Y[u] + Yellow(u,v)
else if alt == dist[v] AND Y[u]+Yellow(u,v) > Y[v]:
prev[v] ← u
Y[v]← Y[u] + Yellow(u,v)
Explanation:
In the else part that we added, the algorithm decides between alternative shortest paths (with identical costs, hence we have if alt == dist[v]) and picks the one that has more yellow edges.
Note that this will still find the shortest path in the graph. If there are multiple, it picks the one with higher number of yellow edges.
Proof:
Consider the set of visited nodes Visited at any point in the algorithm. Note that Visited is the set of nodes that are removed from Q.
We already know that for each v ∈ Visited, dist[v] is the shortest path from Dijkstra Algorithm's proof.
We now show that for each v ∈ Visited, Y[v] is maximum, and we do this by induction.
When |Visited| = 1, we have Visited = {s}, and Y[s] = 0.
Now suppose the claim holds for |Visited| = k for some k >= 1, we show that when we add a new node u to Visited and the size of Visited grows to k+1, the claim still holds.
Let (t_i,u) represent all edges from a node in Visited to the new node u, for which (t_i,u) is on a shortest path to u, i.e. t_i ∈ Visited and (t_i,u) is the last edge on the shortest path from s to u.
The else part of our algorithm guarantees that Y[u] is updated to the maximum value among all such shortest paths.
To see why, without loss of generality consider this image:
Suppose s-t1-u and s-t2-u are both shortest paths and the distance of u was updated first through t1 and later through t2.
At the moment that we update u through t2, the distance of u doesn't change because S-t1-u and S-t2-u are both shortest paths. However in the else part of the algorithm, Y[u] will be updated to:
Y[u] = Max (Y[t1] + Yellow(t1,u) , Y[t2] + Yellow(t2,u) )
Also from the induction hypothesis, we know that Y[t1] and Y[t2] are already maximum. Hence Y[u] is maximum among both shortest paths from s to u.
Notice that for simplicity without loss of generality the image only shows two such paths, but the argument holds for all (t_i,u) edges.

Recompute distances after node removal

I have a graph with computed distances from the "start" node. Now I'd like to remove one node (except the starting one) and recompute distances (ideally without running Shortest Path First on the whole graph).
I don't know how to google such an algorithm and my attempts seem to be quite complicated (especially when compared to adding a new node).
One way to implement Dijkstra's algorithm is to maintain a set of nodes whose distance from the start needs to be updated. When a node's distance is effectively updated, that node is removed from the set, but all of its neighbours are added to the set. When a node's update has no effect, i.e., when that node's distance doesn't change, the node is removed from the set and no node is added. The halting condition for the algorithm is "no node needs to be updated".
When you remove a node from the graph, all of its neighbours need to be updated to reflect the removal.
So you can simply "relaunch" Dijkstra's algorithm on your graph, with the initial distances from the start node which you already have, and with the set of nodes to be updated initialised with the neighbours of the node that was removed. The updates will naturally propagate to any node that will eventually need to be updated.
Note: If your graph is oriented, only the nodes with an incoming edge from the removed node need to be added to the set of nodes to be updated.
Kudos to #Stef, whose answer I am now extending.
Removing a node that is part of a set of minimal paths may require recalculation of all distances to their end-nodes. Using the pseudocode from Dijkstra's algorithm as found here:
1 function Dijkstra(Graph, source):
2
3 create vertex set Q
4
5 for each vertex v in Graph:
6 dist[v] ← INFINITY
7 prev[v] ← UNDEFINED
8 add v to Q
10 dist[source] ← 0
11
12 while Q is not empty:
13 u ← vertex in Q with min dist[u]
14
15 remove u from Q
16
17 for each neighbor v of u: // only v that are still in Q
18 alt ← dist[u] + length(u, v)
19 if alt < dist[v]:
20 dist[v] ← alt
21 prev[v] ← u
22
23 return dist[], prev[]
the prev array contains the previous node to each node in the minimum spanning tree (= the tree of all shortest paths). So, to remove node r, assuming you still have the dist and prev array from before removal, you could change it to:
function DijkstraRemove(Graph, dist, prev, removed):
create vertex set Q
for each vertex v in Graph:
while (prev[v] != UNDEFINED):
if prev[v] == removed:
add v to Q
dist[v] = UNDEFINED
prev[v] = UNDEFINED
break
else:
v = prev[v]
// continue with line 12 above

dijkstra's algorithm running time with array and priority queue

I'm having difficulty understanding the time of the dijkstra algorithm. Below I put the pseudo code I was analyzing for array. Considering that V are the vertices and E the edges. The Q as an array has its initialization with time O(V), the minimum and the for inside the while would have O(V) of while times O(V + E), then the result would be O(V²), am I correct?
1 function Dijkstra(Graph, source):
2 dist[source] ← 0 // Initialization
3
4 create vertex set Q
5
6 for each vertex v in Graph:
7 if v ≠ source
8 dist[v] ← INFINITY // Unknown distance from source to v
9 prev[v] ← UNDEFINED // Predecessor of v
10
11 Q.add_with_priority(v, dist[v])
12
13
14 while Q is not empty: // The main loop
15 u ← Q.extract_min() // Remove and return best vertex
16 for each neighbor v of u: // only v that is still in Q
17 alt ← dist[u] + length(u, v)
18 if alt < dist[v]
19 dist[v] ← alt
20 prev[v] ← u
21 Q.decrease_priority(v, alt)
22
23 return dist[], prev[]
Below I put the pseudo code I was analyzing for priority queue. Now, the Q as an priority queue has its initialization with time O(V), the minimum and the for inside the while would have O(V) of while times O(1 + ElogV), then the result would be O(VElogV), am I correct? Considering the worst case is E = (V - 1), then the result could not be O(V²logV), why the value I find on the web is O(ElogV)? why with priority queue is faster than array?
1 function Dijkstra(Graph, source):
2
3 create vertex set Q
4
5 for each vertex v in Graph: // Initialization
6 dist[v] ← INFINITY // Unknown distance from source to v
7 prev[v] ← UNDEFINED // Previous node in optimal path from source
8 add v to Q // All nodes initially in Q (unvisited nodes)
9
10 dist[source] ← 0 // Distance from source to source
11
12 while Q is not empty:
13 u ← vertex in Q with min dist[u] // Node with the least distance
14 // will be selected first
15 remove u from Q
16
17 for each neighbor v of u: // where v is still in Q.
18 alt ← dist[u] + length(u, v)
19 if alt < dist[v]: // A shorter path to v has been found
20 dist[v] ← alt
21 prev[v] ← u
22
23 return dist[], prev[]
The Q as an array has its initialization with time O(V), the minimum and the for inside the while would have O(V) of while times O(V + E), then the result would be O(V²), am I correct?
If that was correct, the time complexity would be O(V² + VE), and O(VE) would dominate (since V <= E on a 'useful' graph), giving you O(VE) for the whole algorithm. But you are NOT correct in your analysis, which is why the resulting time complexity is O(V²).
You are correct that the min() operation inside the WHILE loop has O(V) and thus O(V²) for the whole algorithm, but for the FOR loop, it's O(E) for the WHOLE duration of the algorithm, not the individual iterations. This is because you remove each vertex from Q exactly once, and you inspect all outgoing edges from each removed vertex. In other words, you inspect all edges, thus O(E).
Now, the Q as an priority queue has its initialization with time O(V), the minimum and the for inside the while would have O(V) of while times O(1 + ElogV), then the result would be O(VElogV), am I correct?
No. the time complexity of the min() operation and the FOR loop would depend on what data structure is used as the priority queue. Assuming that you are using a min-heap as the priority queue, min() will take O(logV), and the FOR loop will take a TOTAL of O(ElogV), which dominates, and becomes the total time complexity of the algorithm.
Here's a link to another answer that explains how to analyze the time complexity of Dijkstra's algorithm depending on which data structure you use to implement the priority queue:
Complexity Of Dijkstra's algorithm

Djikstra's algorithm: Do I iterate through the neighbors or the children?

I'm looking at Djikstra's algorithm in pseudo-code on Wikipedia
1 function Dijkstra(Graph, source):
2
3 create vertex set Q
4
5 for each vertex v in Graph: // Initialization
6 dist[v] ← INFINITY // Unknown distance from source to v
7 prev[v] ← UNDEFINED // Previous node in optimal path from source
8 add v to Q // All nodes initially in Q (unvisited nodes)
9
10 dist[source] ← 0 // Distance from source to source
11
12 while Q is not empty:
13 u ← vertex in Q with min dist[u] // Source node will be selected first
14 remove u from Q
15
16 for each neighbor v of u: // where v is still in Q.
17 alt ← dist[u] + length(u, v)
18 if alt < dist[v]: // A shorter path to v has been found
19 dist[v] ← alt
20 prev[v] ← u
21
22 return dist[], prev[]
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
and the part that's confusing me is line 16. It says for each neighbor but shouldn't that be for each child (i.e. for each neighbor where neighbor != parent). Otherwise I don't see the point of setting the parent in line 20.
The previous node is set on line 20:
prev[v] ← u
This can only happen if line 14 is executed:
remove u from Q
So, for any v, prev[v] cannot be in Q - it was previously removed, and it will never return to Q (within the loop starting at 12, items are not added anymore to Q). This is the same as saying for any u, prev[u] cannot be in Q - asides from changing the name of the variable, it says the same thing.
In the question you say that about line 16:
it says for each neighbor
But, if you look at the pseudocode, it actually says
for each neighbor v of u: // where v is still in Q.
So, prev[u] will not be iterated over - it's not in Q.
For what it's worth, I think the pseudocode is a bit sloppy and confusing // where v is still in Q should not be a comment. It doesn't clarify or explain the rest of the code - it alters the meaning, and should be part of the code. Perhaps that confused you.
Ultimately, Dijkstra's algorithm computes something called a shortest-path tree, a tree structure rooted at some starting node where the paths in the tree give the shortest paths to each node in the graph. The logic you're seeing that sets the parent of each node is the part of Dijkstra's algorithm that builds the tree one node at a time.
Although Dijkstra's algorithm builds the shortest-path tree, it doesn't walk over it. Rather, it works by processing the nodes of the original path in a particular order, constantly updating candidate distances of nodes adjacent to processed nodes. This means that in the pseudocode, the logic that says "loop over all the adjacent nodes" is correct because it means "loop over all the adjacent nodes in the original graph." It wouldn't work to iterate over all the child nodes in the generated shortest-path tree because that tree hasn't been completely assembled at that point in the algorithm.

minimum penalty path in weighted graph

Consider an undirected graph containing N nodes and M edges. Each edge Mi has an integer cost, Ci, associated with it.
The penalty of a path is the bitwise OR of every edge cost in the path between a pair of nodes, A and B. In other words, if a path contains edges M1,M2,...,Mk then the penalty for this path is C1 OR C2 OR ... OR Ck.
Given a graph and two nodes, A and B, find the path between A and B having the minimal possible penalty and print its penalty; if no such path exists, print −1 to indicate that there is no path from A to B.
Note: Loops and multiple edges are allowed.
constraints:
1≤N≤103
1≤M≤103
1≤Ci<1024
1≤Ui,Vi≤N
1≤A,B≤N
A≠B
this question is asked in a contest and its over I went through the tutorial but could not get it. can anyone explain or give the answer how to proceed?
It can be solved using Dynamic programming by following the recursive formula:
D(s,0) = true
D(v,i) = false OR D(v,i) OR { D(u,j) | (u,v) is an edge, j or c(u,v) = i }
Where s is the source node.
The idea is D(v,i) == true if and only if there is a path from s to v with weight of exactly i.
Now, you iteratively modify the graph in your dynamic programming, until it converges (which is at most after n iterations).
This is basically a variant of Bellman-Ford algorithm.
When you are done creating the DP table for the solution, the minimal path is min { x | D(t,x) = true} (where t is the target node).
Time complexity is O(m*n*log_2(R)), where R is the maximal weight allowed (1024 in your case).
What you are looking for is Dijkstra's Algorithm. Rather than adding the weight for each node, you should be ORing it.
So, the pseudo-code would be as follows (modified from the wikipedia example):
1 function Dijkstra(Graph, source):
2
3 create vertex set Q
4
5 for each vertex v in Graph: // Initialization
6 dist[v] ← INFINITY // Unknown distance from source to v
7 prev[v] ← UNDEFINED // Previous node in optimal path from source
8 add v to Q // All nodes initially in Q (unvisited nodes)
9
10 dist[source] ← 0 // Distance from source to source
11
12 while Q is not empty:
13 u ← vertex in Q with min dist[u] // Source node will be selected first
14 remove u from Q
15
16 for each neighbor v of u: // where v is still in Q.
17 alt ← dist[u] OR length(u, v)
18 if alt < dist[v]: // A shorter path to v has been found
19 dist[v] ← alt
20 prev[v] ← u
21
22 return dist[], prev[]
Note the OR on line 17.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll,ll > pr;
vector <pr> adj[10005];
bool visited[10005][10005];
int main(){
ll n,m;
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=m;i++){
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
adj[u].push_back(make_pair(v,w));
adj[v].push_back(make_pair(u,w));
}
ll source,destination;
scanf("%lld%lld",&source,&destination);
queue<ll> bfsq;
bfsq.push(source);// source into queue
bfsq.push(0);//
while(!bfsq.empty()){
ll u=bfsq.front();
bfsq.pop();
ll cost=bfsq.front();
bfsq.pop();
visited[u][cost]=true;
for(ll i=0;i<adj[u].size();i++){
ll v=adj[u][i].first;// neighbor of u is v
ll w2=adj[u][i].second;//// u is connected to v with this cost
if(visited[v][w2|cost]==false){
visited[v][w2|cost]=true;
bfsq.push(v);
bfsq.push(w2|cost);
}
}
}
ll ans=-1LL;
for(ll i=0;i<1024;i++){
if(visited[destination][i]==true){
ans=i;
break;
}
}
printf("%lld\n",ans);
return 0;
}

Resources