You are on page 1of 2

Algorithms Mini Field Guide (v1) Fast Fourier Transform O(n log n) Strongly Connected Components O(n)

The Fast Fourier Transform in the scope of our knowledge thus Us for most edge removal problems, use this to check if still
Written by: Krishna Parashar far is used for Polynomial Multiplication. We want to know the strongly connected.
Published by: The OCM coefficient of (p · q)(x) knowing only the coefficients of p(x) and Properties:
Inspired by: Raemond Bergstrom-Wood. q(x). The naive way is the one we all use in Algebra which runs
• If the explore subroutine is started at node u, then it will
in O(n2 ). Here is a faster algorithm:
Basic Properties of Logarithms terminate precisely when all nodes reachable from u have
1. Take the coefficients of p(x) and q(x) and plug them into been visited.
y = logb (x) iffx = by the FFT with the Roots of Unity (We need 2n + 1 points).
logb (xy) = logb (x) + logb (y) O(n log n) • The node that receives the highest post number in a
log (x)
logb (x) = logb (c) logc (x) = logc (b) depth-first search must lie in a source strongly connected
c 2. From the FFT we get the roots of unity evaluated at p(x) component.
1 √
logb (xn ) = n logb (x) xa xb = x(a+b) (xa )b = x(ab) x( 2 ) = x and q(x) and we multiply the respected values from each
a root together to get 2n + 1 respective pairs of values of • If C and C are strongly connected components, and there
x(a−b) = xxb is an edge from a node in C to a node in C, then the
(p · q)(x). O(n)
Basic Series highest post number in C is bigger than the highest post
3. Finally we interpolate these points using the inverse FFT
n
n(n+1) number in C.
to get the coefficients of (p · q)(x). O(n log n)
P
Arithmetic Series (Sequential Integers): k= 2
k=1 Run Time: O(n)
n Evaluation: < values > = FFT(< coef f >, w)
Big Picture: Topologically sort the graph; reverse the edges;
n2 Interpolation: < coef f > = (1/n) FFT(< values >, w−1 )
P
Arithmetic Series (Sequential Odd Ints): 2k − 1 =
k=1 topologically sort again; ff we reach a new source the resulting
n
n(n+1)(2n+1) function FFT(A, w) traversal is new SCC; continue till end of list.
k2 =
P
Artihmetic Series (Square): 6
Finite Input: Coefficient representation of a polynomial A(x) Algorithm:
k=1
n
a(1−r n )
of degree less than or equal to n1, • Run depth-first search on G.
ark−1 =
P
Geometric Series: 1−r where n is a power of 2w, an nth root of unity
k=1
Output: Value representation A(w_0),...,A(w_n1) • Run the undirected connected components algorithm

Infinite Geometric Series:
P
ark−1 = a (which count uses a counter to count the number of
1−r
k=1 if w = 1: return A(1) components in G) on G, and during the depth-first search,
Formal Limit Definition of O, Θ, and Ω express A(x) in the form A_e(x^2) + xA_o(x^2) process the vertices in decreasing order of their post

call FFT(A_e, w^2) to evaluate A_e at even powers of w numbers from step 1.
≥ 0(∞) f (n) ∈ Ω(g(n))
f (n)  call FFT(A_o, w^2) to evaluate A_o at even powers of w
lim < ∞(0) f (n) ∈ O(g(n)) Breadth First Search O(V + E) (Queue)
n→∞ g(n) 
= c, 0 < c < ∞ f (n) ∈ Θ(g(n)) for j = 0 to n 1:
compute A(w_j) = A_e(w^2j) + w^j A_o(w^2j) Input: Graph G = (V, E), directed or undirected; vertex s V
Topological Sort O(V + E) return A(w_0),...,A(w_n1) Output: For all vertices u reachable from s, dist(u) is set
Constraints: A directed graph G is acyclic if and only if a to the distance from s to u.
depth-first search of G yields no back edges. Formally, we say a This process happens recursively.
topological sort of a directed acyclic graph G is an ordering of def bfs(G,s):
Search Algorithms for all u in V:
the vertices of G such that for every edge (vi , vj ) of G we have
i < j. If DAG is cyclic then no linear ordering is possible. Depth First Search O(V + E) (Stack) dist(u) = infinity
Topological Sort returns a list with all nodes pointing left such Explores all the way down to a tree, then climbs back up and dist(s) = 0
that basically all parents come before any children (excluding explores alt paths. Use for Topological Sort and Finding Q = [s] (Queue containing just s)
sources). We order a graph from the highest post number in a Connected Components. (pre(u) < pre(v) < post(v) < post(u)) while Q is not empty:
decreasing order. u = eject(u)
def explore(G,v): #Where G = (V,E) of a Graph for all edges (u,v) in E:
Thus we create singly connected component from a DAG with
Input: G = (V,E) is a graph; v V if dist(v) = infinity:
several strongly connected components, each a unique source and
Output: visited(u) is set to true for all nodes u inject(Q,v)
unique sink in the DAG. There are multiple topological sorting
reachable from v dist(v) = dist(u) + 1
possible. Used for Runtime Compiling or Scheduling.
visited(v) = true
pre/post previsit(v)
[u[v v]u] is a Tree/Forward Edge Dijkstra’s Algorithm O(V + E) log V (Binary Heap)
[v[u u]v] is a Back Edge for each edge(v,u) in E:
[v v][u u] is a Cross Edge
if not visited(u): Objective is to find shortest path. Standard Data Structure is
explore(u) Priority Queue.
Master’s Theorem postvisit(v)
If def dijkstra(G,l,s):
for all u in V:
T (n) = aT (dn/be) + O(nd ) for a > 0, b > 1, and d ≥ 0, def dfs(G):
for all v in V: dist(u) = infinity
then, prev(u) = nil
 if not visited(v):
 O(nd ) if d > logb a dist(s) = 0
T (n) = O(nd logn) if d = logb a explore(v)
H = makequeue(V) # using dist values as keys
O(nlogb a ) if d < lobb a

Previsit = count till node added to the queue while H is not empty:
Branching Factor: a Postvisit = count till you leave the given node u = deletemin(H)
Depth of Tree = logb n A directed Graph has a cycle if and only if it a back edge found for all edges (u,v) in E:
Width of Tree: alogb n = nlogb a during DFS. if dist(v) > dist(u)+l(u,v)
dist(v) = dist(u)+l(u,v) Input: A connected undirected graph G = (V,E) with edge Huffman Encoding
prev(v) = u weights w A means to encode data using the optimal number of bits for
decreasekey(H,v) Output: A minimum spanning tree defined by the edges X each character given a distribution.
Bellman Ford Algorithm O(V · E) for all u in V: Set Cover Algorithm (Polynomial Time)
Objective is to find shortest path allowing for negative edges. makeset(u) Input: A set of elements B; sets S1,...,Sm
X = {} Output: A selection of the S_i whose union is B.
procedure shortest-paths(G, l, s) Sort the edges E by weight Cost: Number of sets picked.
Input: Directed graph G = (V, E); for all edges {u,v} in E, in increasing order of weight:
edge lengths {l_e: e in E} with no negative cycles; if find(u) != find(v): Repeat until all elements of B are covered:
vertex s in V add edge {u,v} to X Pick the set Si with the largest number of
Output: For all vertices u reachable from s, union(u,v) uncovered elements.
dist(u) is set to the distance from s to u.
for all u in V: The above algorithm utilizes disjoint sets to determine whether
adding a given edge creates a cycle. Basically by checking
Disjoint Sets Data Structure
dist(u) = infinity
prev(u) = nil whether or not both sets have the same root ancestor. Contains a function, ”find” that returns the root a given set. pi
refers to the parent node. rank refers to the height subtree
dist(s) = 0 hanging form that node (number of levels below it).
repeat |V|-1 times: • For any x, rank(x) < rank(π(x)).
for all e in E: • Any root node of rank k has at least 2k nodes in its tree.
update(e) Properties of Trees (Undirected Acyclic Graphs)
• If there are n elements overall, there can be at most 2nk
• A tree with n nodes has n-1 edges nodes of rank k. The maximum rank is logn.
Directed Acyclic Graphs • Any connected undirected graph G(V,E), with
• Every DAG has a source and sink |E| = |V | − 1 is a tree
def makeset(x): // O(1)
• A directed graph has a cycle if and only if its depth-first pi(x) = x
• An undirected graph is a tree if and only if there is a rank(x) = 0
search reveals a back edge. unique path between any pair of nodes.
• In a DAG, every edge leads to a vertex with a lower post
Cut Property def find(x): // O(E log V)
number. while x != pi(x):
Suppose edges X are part of a minimum spanning tree of
• Every directed graph is a DAG of its strongly connected x=pi(x)
G = (V, E). Pick any subset of nodes S for which X does not
components. return x
cross between S and V-S, and let e be the lightest edge across the
• If the explore subroutine is started at node u, then it will partition. Then X ∪ e is part of some Minimum Spanning Tree.
terminate precisely when all nodes reachable from u have def union(x,y): // O(E log V)
been visited Prim’s Algorithm O(E log E) if find(x) == find(y):
Objective is to also find the MST. Alternative to Kruskal’s return
• The node that receives the highest post number in a elif rank(find(x)) > rank(find(y)):
depth-first search must lie in a source strongly connected Algorithm; Similar to Dijkstra’s)
Standard Data Structure is Priority Queue. (If Dense: |E| at pi(find(y)) = find(x)
component else:
most |V 2 |)
• If C and C’ are strongly connected components, and there On each iteration, the subtree defined by x grows by one edge, pi(find(x))=find(y)
is an edge from a node in C to a node in C’, the the the lightest between a vertex in S and a vertex outside S. if rank(find(x)) == rank(find(y)):
highest post number in C is bigger than the highest post rank(find(y)) = rank(find(y)) + 1
number in C’. procedure prim(G, w)
• In any path of a DAG, the vertices appear in an increasing Input: A connected undirected graph G = (V, E) with weights Path Compression
linearized order allowing you to run Dijkstra’s Algorithm Output: A minimum spanning tree defined by the array prev function find(x):
in O(n) for all u in V : if x != pi(x): pi(x) = find(pi(x))
cost(u) = infinity return pi(x)
Greedy Algorithms prev(u) = nil
Pick any initial node u_0 Using path compression allows for an amortized cost of O(1) for
Definitions
cost(u_0) = 0 out Disjoint Set’s union(x, y) and f ind(x) operations.
A Greedy Algorithm always takes the cheapest least weight H = makequeue (V) (priority queue with cost-values as keys)
edge for its next step, no matter the future consequences. Union Find
while H is not empty:
A Tree is an acyclic, undirected, connected graph with |V | − 1 v = deletemin(H) Uses Disjoint Sets Data Structure
edges (or for MST exactly |V | − 1 edges). for each {v, z} in E: Runs in per operation Olog ∗ n which is the number of times you
A Fringe is all the vertices exactly one hop from you current if cost(z) > w(v, z): can take a log of n before it becomes 1 or less. It is very slow and
vertex. cost(z) = w(v, z) for all practical cases is constant.
prev(z) = v Basically if find(x) and find(y) return the same value they are in
Kruskal’s MST Algorithm O(E log E)
decreasekey(H, z) the same graph so do nothing, else add the edge. Then union(x,
(If Dense: |E| at most |V 2 |) y).
Sort edges using a sorting algorithm then repeatedly add the Union: Worst case is O(logN ) Avg for all Ops is O(nlog ∗ n)
next lightest edge that doesn’t produce a cycle (i.e. only visit where n is number of elements in Data Structure.
new vertices).

You might also like