How to get the longest path in a DAG starting at a fixed node? - directed-acyclic-graphs

I want to know how to get the longest path in a DAG starting from the node 0(the smallest node)
I searched wiki and got the following algorithm:
algorithm dag-longest-path is
input:
Directed acyclic graph G
output:
Length of the longest path
length_to = array with |V(G)| elements of type int with default value 0
for each vertex v in topOrder(G) do
for each edge (v, w) in E(G) do
if length_to[w] <= length_to[v] + weight(G,(v,w)) then
length_to[w] = length_to[v] + weight(G, (v,w))
return max(length_to[v] for v in V(G))
but I don't know how to implement it, of course the following code I wrote doesn't work:(topo is the topological sorted nodes)
public static int longestPath(int[] topo){
int[] dist = new int[topo.length];
for(int i:topo){
if(isArc(node,i)){
if(dist[i]<dist[node]+1){
dist[i] = dist[node] + 1;
}
}
}
return getMax(dist);
}
How should I do? Thanks!
Besides, could you give me an algorithm to calculate the number of different paths from 0 to n-1?

Related

How to optimize this graph/tree problem counting distance between two nodes in C++?

Problem is to find sum of distance between two nodes in a tree
INPUT: 6 [[0,1],[0,2],[2,3],[2,4],[2,5]]
shows nodes
OUTPUT: [8,12,6,10,10,10]
Explanation: The tree is shown above.
We can see that dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
equals 1 + 1 + 2 + 2 + 2 = 8.
Hence, answer[0] = 8, and so on.
This is my code, I have solved it but this gives TLE and unable to optimize this solution
How I can optimize this graph problem.
class Solution {
public:
vector<int> sumOfDistancesInTree(int n, vector<vector<int>>& edges) {
vector<int> g[n];
map<pair<int,int>,int> m;
for(auto i:edges){
g[i[0]].push_back(i[1]);
g[i[1]].push_back(i[0]);
}
for(int i=0;i<n;i++){
queue<int> q;
q.push(i);
vector<bool> vis(n,0);
vis[i]=1;
int incr=1;
while(!q.empty()){
int k=q.size();
while(k--){
int t=q.front();q.pop();
for(int j=0;j<g[t].size();j++){
if(!vis[g[t][j]] && g[t][j]!=i){
m[{i,g[t][j]}]+=incr;
q.push(g[t][j]);
vis[g[t][j]]=1;
}
}
}
incr++;
}
}
vector<int> res(n,0);
for(auto i:m){
res[i.first.first]+=i.second;
}
return res;
}
};
As I can see you are using bfs for every node to find the distance.
What you can do is use dynamic programming
Follow the steps below to solve the problem
Initialize a vector dp to store the sum of the distances from each node i to all the leaf nodes of the tree.
Initialize a vector leaves to store the count of the leaf nodes in the sub-tree of node i considering 1 as the root node.
Find the sum of the distances from node i to all the leaf nodes in
the sub-tree of i considering 1 as the root node using a modified
Depth First Search Algorithm.
Let node a be the parent of node i
leaves[a] += leaves[i] ;
dp[a] += dp[i] + leaves[i]
Use the re-rooting technique to find the distance of the remaining
leaves of the tree that are not in the sub-tree of node i. To
calculate these distances, use another modified Depth First Search
(DFS) algorithm to find and add the sum of the distances of leaf
nodes to node i.
Let a be the parent node and i be the child node, then
Let the number of leaf nodes outside the sub-tree i that are present in the sub-tree a be L
L = leaves[a] – leaves[i] ;
dp[i] += ( dp[a] – dp[i] ) + ( L – leaves[i] ) ;
leaves[i] += L ;

the number of possible paths in graph

I have to calculate the number of possible paths in undirected graph
Example: I have a undirected graph with 4 node. The vertices: 1->2; 2>3; 2->4.
So the number of possible paths is 12
(1->2; 1->2->3; 1->2->4; 2->1; 2->3; 2->4; 3->2; 3->2->4...and so on);
Because I don't know exactly how you wrote your code, all I can give you is some sort of a pseudo-code explanation :
function getPathsFromNode(node)
mark node
c = 0;
foreach neighbour in adjacent nodes of node
if neighbour is not marked
c += getPathsFromNode(neighbour) + 1
return c
function main()
n = 0
foreach node in graph
n += getPathsFromNode(node)
print("paths = ", n)
Basically it's just a DFS for every node of the graph.

Unable to Input the graph

I am solving the problem http://www.spoj.com/problems/SHOP/ in C++ but I am unable to figure out how to input the graph to furhter apply Dijkstra algorithm in it.
Here is the graph format-
4 3
X 1 S 3
4 2 X 4
X 1 D 2
First line indicated the columns & rows of the grid ,"S" & "D" -indicates source and destination respetively Numbers -indicates the time required to pass that block,"X"-indicates the no entry zone.
HOw to convert the following graph in nodes and edges as required by DIjkstra algorithm.I don't know how to convert the map into a graph.
There is no need to convert. Just imagine that you are in some point (i,j). (I assume that you have four moves allowed from each square). Then, you can go to either (i + 1, j), (i, j + 1), (i - 1, j), (i, j - 1) if:
1) That index is inside the table
2) That index is not marked with X
So, you give the position of square S to your Dijkstra algorithm. And each time you add the new set of allowed squares to your data structure. Once your reach the position of D you print it.
Besides, this problem does not seem weighted to me so you can use a simple BFS as well using a queue. But if you want to use Dijkstra and going to different squares has different costs. The you use a priority queue instead of queue.
For example, you can use a set data structure like this:
int dist[][]; // this contains the cost to get to some square
//dist is initialized with a large number
struct node{
int i, j; //location
node(int ii, int jj){
i = ii;
j = jj;
}
bool operator < (node &n)const{ //set in c++ will use this to sort
if(dist[i][j] == dist[n.i][n.j]) return i < n.i || j < n.j; //this is necessary
return dist[i][j] < dist[n.i][n.j];
}
};
set <node> q;
int main(){
//initialized dist with large number
dist[S.i][S.j] = 0; //we start from source
q.push(node(S.i, S.j));
while(true){
//pick the first element in set
//this element has the smallest cost
//update dist using this node if necessary
//for every node that you update remove from q and add it again
//this way the location of that node will be updated in q
//if you see square 'D' you are done and you can print dist[D.i][D.j]
}
return 0;
}
There is no need to convert the matrix into nodes and edges.
You can make structure which contain (row number,column number ,time ) where time will represent how much time taken to reach this coordinate from source. now make a min heap of this structure with key as time. now extract element (initially source will be in min heap with time as 0) from min heap and push the adjacent elements into min heap(only those elements which are not visited and do not contain a X) set visited of extracted element true.Go on like this until extracted element is not destination.

finding a element in a matrix with the minimum cost starting from one point

I have n*n matrix and I want to find the element from the matrix that has the minimum cost, the cost of a node meaning cost = Manhattandistance(startingnode,node) + costof(node) where starting node is a node in which perspective I am searching!
I did it just with 4 for loops and it works but I want to optimize it and I did something like a bfs: I used a queue and added first the starting node, after that in a while loop I pop ed the node from the queue and added to the queue all the elements around that node with the Manhatttan 1. I do this while the distance of the node that I just popped from the queue + the minimum price from the whole matrix (which I know from the start) is less than the minimum price that I have just found ( I compare the price of the node I just popped with min) if it's bigger I stop searching because the minimum node I found is the lowest possible value. The problem is this algorithm is to slow possibly because I use a std::queue? and it works in more time than the 4 for loops version. (I also used a flags matrix to see if the element I am inspecting when I add to the queue has been already added). The most time consuming block of code is the part I expand the node don't know why I just inspect if the element is valid I mean it's coordinates are less than n and bigger than 0 if ok I add the element to the queue!
I want to know how can I improve this or if it's another way to do it! Hope I was explicit enough.
this is the part of code that takes to long:
if((p1.dist + 1 + Pmin) < pretmincomp || (p1.dist + 1 + Pmin) < pretres){
std::vector<PAIR> vec;
PAIR pa;
int p1a=p1.a,p1b = p1.b,p1d = p1.dist;
if(isok(p1a+1,p1b,n)){
pa.a = p1a + 1;
pa.b = p1b;
pa.dist = p1d + 1;
vec.push_back(pa);
}
if(isok(p1a-1,p1b,n)){
pa.a = p1a - 1;
pa.b = p1b;
pa.dist = p1d + 1;
vec.push_back(pa);
}
if(isok(p1a,p1b+1,n)){
pa.a = p1a;
pa.b = p1b + 1;
pa.dist = p1d + 1;
vec.push_back(pa);
}
if(isok(p1a,p1b -1 ,n)){
pa.a = p1.a;
pa.b = p1.b - 1;
pa.dist = p1d + 1;
vec.push_back(pa);
}
for(std::vector<PAIR>::iterator it = vec.begin();
it!=vec.end(); it++){
if(flags[(*it).a][(*it).b] !=1){
devazut.push(*it);
flags[(*it).a][(*it).b] = 1;
}
}
You are dealing with a shortest path problem, which can be efficiently solved with BFS (if the graph is unweighted) or A* algorithm - if you have some "knowledge" on the graph and can estimate how much it will "cost" you to find a target from each node.
Your solution is very similar to BFS with one difference - BFS also maintains a visited set - of all the nodes you have already visited. The idea of this visited set is that you don't need to revisit a node that was already visited, because any path through it will be not shorter then the shortest path you will find during the first visit of this node.
Note that without the visited set - each node is revisited a lot of times, which makes the algorithm very inefficient.
Pseudo code for BFS (with visited set):
BFS(start):
q <- new queue
q.push(pair(start,0)) //0 indicates the distance from the start
visited <- new set
visited.add(start)
while (not q.isEmpty()):
curr <- q.pop()
if (curr.first is target):
return curr.second //the distance is indicated in the second element
for each neighbor of curr.first:
if (not set.contains(neighbor)): //add the element only if it is not in the set
q.push(pair(neighbor,curr.second+1)) //add the new element to queue
//and also add it to the visited set, so it won't be re-added to the queue.
visited.add(neighbot)
//when here - no solution was found
return infinity //exhausted all vertices and there is no path to a target

Finding Diameter of a Tree

I have written code for finding the diameter of binary tree. But I am unable to figure out where is it going wrong . The two functions that I have written and their definition are as follows :-
int btree::diameteroftree(node* leaf)
{
if (leaf==NULL)
return 0;
int lheight = hieghtoftree(leaf->left);
int rheight = hieghtoftree(leaf->right);
int ldiameter = diameteroftree(leaf->left);
int rdiameter = diameteroftree(leaf->right);
return max(lheight + rheight + 1,max(ldiameter,rdiameter));
}
int btree::hieghtoftree(node* leaf)
{
int left=0,right=0;
if(leaf==NULL)
return -1;
else
{
left=hieghtoftree(leaf->left);
right=hieghtoftree(leaf->right);
if(left > right)
return left +1;
else
return right+1;
}
}
I am unable to figure out where am I going wrong here . Can someone let me know ...
You want to return the number of nodes on the longest path. Therefore, the problem in your algorithm is this line:
return max(lheight + rheight + 1,max(ldiameter,rdiameter));
where
rootDiameter = lheight + rheight + 1
is the length of the path from the deepest node of the left tree to the deepest node of the right tree. However, this calculation is not correct. A single node returns a height of 0, so it will not be counted. You have two options:
Change hieghtoftree to return the number of nodes on the deepest path and not the number of "hops"
Address this problem in your summation
.
return max(lheight + rheight + 3,max(ldiameter,rdiameter));
In a directed, rooted tree, there is always at most one path between any pair of nodes and the longest path to any node always starts at the root. It follows that the diameter is simply the height of the entire tree height(root), which can be computed with the recursion
height(leaf) = 0
height(node) = max(height(node.left), height(node.right)) + 1
EDIT: the page you link to in the comment describes the diameter of an undirected tree. You need a different tree representation, e.g. an adjacency matrix.
Consider a 3-node tree with root R and 2 leaves L1, L2. Then heightoftree(L1) == heightoftree(L2) == -1. Diameteroftree(R) would therefore be (-1)+(-1)+1 = -1 ?!?
I suggest return -1; --> return 0;
and
return max(lheight + rheight + 1,max(ldiameter,rdiameter)); --> return max(lheight + rheight + 2,max(ldiameter,rdiameter));
The result would be the number of edges on the path. If you count the number of nodes, then add one or subtract one from the final result according to your need.