0% found this document useful (0 votes)
32 views16 pages

DP On Graphs

- Dynamic programming can be applied to directed acyclic graphs (DAGs) as the order of calculations is important in DP problems. - Almost every DP problem can be represented as a DAG with nodes as states and edges as transitions. - Binary lifting can be used to solve queries on graphs and trees more efficiently in O(logN) time by precomputing successor/ancestor relationships for powers of 2.

Uploaded by

Anderson Vieira
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views16 pages

DP On Graphs

- Dynamic programming can be applied to directed acyclic graphs (DAGs) as the order of calculations is important in DP problems. - Almost every DP problem can be represented as a DAG with nodes as states and edges as transitions. - Binary lifting can be used to solve queries on graphs and trees more efficiently in O(logN) time by precomputing successor/ancestor relationships for powers of 2.

Uploaded by

Anderson Vieira
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

DP on Graphs

DP on DAGs
- Only on DAG (Directed Acyclic Graph)
[ Directed graph without a cycle ]

Why DP is applied only on DAG?


- In DP, we need to run base condition first,
then the other DP values are calculated
using it. So, order is important in DP
Eg.
dp[0]=1
dp[n] = dp[n-1] + dp[n-2]

Almost every DP problem can be


represented as DAG
- Like the staircase climbing question (or nth
fibonacci number problem) discussed in
previous class can be represented as:
- Each node would be a state
- And arrows are transition

1. What is the shortest path from node a to


node b?
[ Assume u have topologically sorted nodes
in a DAG, in vector topo ]
// adj is adjacency list of graph
dp[n] = INFINITY for all n
dp[a]=0;
Let a_ind = index of a in topo sort
In topological order
dp[i] represent the min distance to reach node i
for(int i=0; i<topo.size(); i++)
{
int u=topo[i];
if(i<a_ind)
continue;
for(auto v: adj[u])
{
dp[v] = min(dp[v], dp[u] + 1)
}
}
cout<<dp[b];

2. What is maximum distance path from


node a to b?
- dp[n]= (-INFINTIY) for all n
- dp[v] = max(dp[v], dp[u] + 1)

3. How many different paths node from a


to b?
- dp[n] = 0 for all n
- dp[a] = 1
dp[i] = different paths to reach i from a
Let a_ind= Index of a in topo sort
In topological order
for(int i=0; i<topo.size(); i++)
{
int u=topo[i];
if(i<a_ind)
continue;
for(auto v: adj[u])
{
dp[v] = dp[v] + dp[u]
}
}
cout<<dp[b];
Q. CSES Game Routes:
https://cses.fi/problemset/task/1681

DP on Directed Graph with Cycles

Q. Codechef - Visiting Friends


https://www.codechef.com/problems/MCO1640
5
- Graph can contain many cycles
- We need to convert it into a DAG
(Replace all the SCCs by by 1 node with
their ci value as sum of all ci values in it)
- Now, just apply DP
Dp[i] = If I start at city i, then number of people i
can meet
Initialise dp[i] = 0 for all nodes in this new DAG
graph
Process in reverse topological sorting order
for(auto u: rev(topo))
{
for(auto v: adj[u])
{
// I can reach any of its successors from u
(but not all), so we take max of all dp[]
values of successors
dp[u]=max(dp[u],dp[v]);
}
dp[u] +=c[u];
// As c[u] people will always be visited if I
start at u
}

First, try to solve the question by yourself. If you


find it difficult to implement, you can refer my
submission here:
https://www.codechef.com/viewsolution/404826
95

Successor Graphs/Functional Graphs


Given (x,k)
Q. If you start at node x and move k steps
forward, find the node where you will reach
? (or Find kth successor of x)

- Each node has a unique successor


Let length from x to 1 = p
Let length of cycle = L

If( k<=p)
{
ans = Kth successor of p
}
Else
{
k-=p
ans = (k%L)th successor of 1
(1 is the node where cycle starts)
}

O( N ) where N = no. of nodes

Q. Now, do the same thing for q queries


Where q<=10^5, N <=10^5
Each query is of form (x,k)

- Above method takes O(q.N) which gives


TLE
- Also, if we precompute all the values, then it
takes O(N^2) , which gives MLE
- So, we solve this using Binary Lifting

Binary Lifting

- Every distance can be divided into powers


of 2 - [with at max log2(n) terms]
11 = 2^3 + 2^1 + 2^0
10 = 2^3 + 2^1

- Using this, we can answer every query in


log(n) time, if we precompute the answer of
all the powers of 2
Log(n) values is always <= 30

const int K=30;


int dp[MAXN + 1][K+1];
// dp[i][j] = The node which we will reach if
we start at node i and move 2^j steps
(jumps)
// or dp[i][j]= (2^j)th successor of node i

// dp[i][0] = immediate successor of i


// Because 20 = 1
// n = no. of nodes
void precompute()
{
for(int i=0; i<n; i++)
{
dp[i][0]= succ(i);
}
for(int j=1; j<=K; j++)
{
for(int i=0; i<n; i++)
{
dp[i][j] = dp[dp[i][j-1]][j-1];
// Divide 2( j ) = 2( j-1 ) + 2( j-1 )
}
}
}
int query(int x, int k)
{
int ans=x;
for(int j=K; j>=0; j--)
{
// In c++ , use (1<<j) for 2j
if( (1<<j) <=k)
{
ans=dp[ans][j];
// Perform 2j jumps
k-=(1<<j);
}
}
}
Eg. If x=1, k=6
ans= dp[x][2] // 2^2=4
k-=4
k=2
ans = dp[ans][1] // 2^1=2
k-=2
k=0

- In query, we just try to find the largest


power of 2 which is <= the number k
(Basically, it is the binary representation
of number)
6 = 110
Pre Computaion : O( N log(N))
Log(N) for 1 query

- Similary, we can also binary lifting to find


kth ancestor of a node in a tree
(Because, in binary tree, each node has
exactly 1 parent except root)
Try this: (Company Queries I)
https://cses.fi/problemset/task/1687
- Using this, we can also find LCA (Least
Common Ancestor) of 2 nodes in a tree
Ref:
https://cp-algorithms.com/graph/lca_bin
ary_lifting.html
Time complexity: O( log(N) ) for 1 query
Pre Computation: O( N log(N))

Floyd’s Cycle Detection in Successor


Graphs
(Hare / Tortoise Algorithm)

Given a successor graph,


1. What is the first node (entry
point) in the cycle ?
2. What is the length of the cycle ?

Keep 2 pointers a and b

Both start at x (Source Node)


a (Tortoise) will move only 1 step at a
time
b (Hare) wil move 2 steps at a time

They will definitely meet at some node


inside the cycle. And, their meeting point
is not necessary for the entry point of
the cycle.

a = succ(x)
b = succ(succ(x))

while (a!=b)
{
a=succ(a)
b=succ(succ(b))
}

Let L = length of cycle


M = Meeting point
X = Starting Point
C = Entry point of cycle

Distance of a = k + p.L + m
Distance of b = k + q.L + m
Distance of b = 2 x Distance of a
k + q.L + m = 2 (k + p.L + m)

(q-2p).L = k + m

Let (q-2p) = z

k+m = L.z
k+m is a multiple of L

K = L.z -m

If I place tortoise at M now, and hare at


X now, and both move 1 step at a time.
Then , they will meet at C (the entry
point)

b=x

while (a!=b)
{
a=succ(a)
b=succ(b)
}
// Now, after this value of a would be C
(entry point)

Now, length of cycle can be easily found


using this.

Try these problems:


Q. Planet Cycles
https://cses.fi/problemset/task/1751

Q. Detect if Linked List contains a cycle


https://www.hackerrank.com/challenges/detect-
whether-a-linked-list-contains-a-cycle/problem

Q. Find the entry point of cycle in a Circular


Linked List
https://leetcode.com/problems/linked-list-cycle-ii
/

You might also like