Skip to main content

Advanced Graph Problems

TL;DR

Tarjan's algorithm finds strongly connected components in O(V + E) single DFS pass, using a recursion stack and low-link values. Bipartite checking uses 2-coloring: attempt to color graph with 2 colors using BFS/DFS; impossible means not bipartite. Euler paths traverse each edge exactly once: existence requires (0 or 2) odd-degree vertices. Network flow concepts: max-flow equals min-cut; Ford-Fulkerson finds max flow by repeatedly finding augmenting paths. These advanced techniques solve problems in connectivity, matching, and resource optimization.

Core Concepts

Strongly Connected Components (SCC)

SCC are maximal vertex subsets where each vertex is reachable from every other vertex.

Key properties:

  • Unique decomposition: Every directed graph has unique SCC decomposition
  • DAG of SCCs: Condensing SCCs creates a DAG
  • Applications: Social networks (finding communities), web crawlers (finding cycles)

Why important: Identifies "super-nodes" for condensed graph analysis.

Tarjan's Algorithm

Tarjan finds all SCCs in single DFS pass using recursion stack and low-link values.

Key concepts:

  • Discovery index: When vertex is first visited
  • Low-link value: Minimum discovery index reachable from vertex
  • Root of SCC: Vertex where low[v] == disc[v]

Algorithm:

  1. DFS from unvisited vertices
  2. Track discovery time and low-link value
  3. Use stack to maintain current path
  4. When low[v] == disc[v], pop stack to find complete SCC

Time complexity: O(V + E) - single DFS pass.

Bipartite Graphs

Bipartite graph has vertices partitioned into two sets with edges only between sets, never within set.

Properties:

  • 2-colorable: Can be colored with 2 colors such that adjacent vertices have different colors
  • No odd cycles: All cycles have even length
  • Applications: Job scheduling (workers and jobs), matching problems

Bipartite checking:

  1. Attempt 2-coloring using BFS/DFS
  2. For each uncolored vertex, assign color 0
  3. For each neighbor, assign opposite color
  4. If conflict (neighbor same color), not bipartite

Euler Paths and Circuits

Euler path traverses each edge exactly once. Euler circuit is Euler path forming cycle.

Existence conditions:

  • Euler circuit exists: Graph connected, all vertices have even degree
  • Euler path exists: Graph connected, exactly 0 or 2 vertices have odd degree
  • Cannot exist: More than 2 odd-degree vertices

Finding Euler path (Hierholzer's algorithm):

  1. If using Euler circuit conditions, start at any vertex
  2. If using path conditions with 2 odd-degree vertices, start at one
  3. Follow edges greedily; when stuck, backtrack and find another starting point
  4. Result is Euler path (may need reversal)

Network Flow Concepts

Flow network has source, sink, and edges with capacities. Flow assigns value to each edge respecting capacity constraints and flow conservation.

Key concepts:

  • Capacity: Maximum flow on edge
  • Flow conservation: Inflow equals outflow (except source and sink)
  • Residual capacity: Remaining capacity after current flow
  • Augmenting path: Path from source to sink with available capacity
  • Max-flow min-cut theorem: Maximum flow equals minimum cut capacity

Ford-Fulkerson approach:

  1. Start with zero flow
  2. While augmenting path from source to sink exists:
    • Find path with positive residual capacity
    • Add minimum residual capacity along path to flow
    • Update residual capacities (forward and backward)

Key Algorithms

Tarjan's SCC Algorithm

Single-pass DFS finding all strongly connected components using discovery times and low-link values.

Bipartite Graph Checking

Two-coloring approach: attempt to color graph with 2 colors; success means bipartite, failure means not.

Euler Path Finding (Hierholzer's Algorithm)

Greedy path following with backtracking to ensure all edges traversed exactly once.

Ford-Fulkerson Maximum Flow

Iterative path augmentation in residual graph until no augmenting paths remain.

Practical Example

from collections import defaultdict, deque

class AdvancedGraph:
def __init__(self):
self.graph = defaultdict(list)

def add_directed_edge(self, u, v):
self.graph[u].append(v)

# Tarjan's Algorithm for SCC
def tarjan_scc(self):
index_counter = [0]
stack = []
lowlinks = {}
index = {}
on_stack = defaultdict(bool)
sccs = []

def strongconnect(v):
index[v] = index_counter[0]
lowlinks[v] = index_counter[0]
index_counter[0] += 1
stack.append(v)
on_stack[v] = True

for w in self.graph[v]:
if w not in index:
strongconnect(w)
lowlinks[v] = min(lowlinks[v], lowlinks[w])
elif on_stack[w]:
lowlinks[v] = min(lowlinks[v], index[w])

if lowlinks[v] == index[v]:
scc = []
while True:
w = stack.pop()
on_stack[w] = False
scc.append(w)
if w == v:
break
sccs.append(scc)

for v in self.graph:
if v not in index:
strongconnect(v)

return sccs

# Bipartite check using 2-coloring
def is_bipartite(self):
color = {}

for start in self.graph:
if start in color:
continue

queue = deque([start])
color[start] = 0

while queue:
u = queue.popleft()
for v in self.graph[u]:
if v not in color:
color[v] = 1 - color[u]
queue.append(v)
elif color[v] == color[u]:
return False

return True

# Euler path detection
def has_euler_path(self):
in_degree = defaultdict(int)
out_degree = defaultdict(int)

for u in self.graph:
for v in self.graph[u]:
out_degree[u] += 1
in_degree[v] += 1

odd_diff = 0
for v in set(list(self.graph.keys()) + list(in_degree.keys())):
diff = out_degree[v] - in_degree[v]
if diff != 0:
if abs(diff) != 1:
return False
odd_diff += 1

return odd_diff == 0 or odd_diff == 2

# Hierholzer's algorithm for Euler path
def euler_path(self):
in_degree = defaultdict(int)
out_degree = defaultdict(int)
graph = defaultdict(list)

for u in self.graph:
for v in self.graph[u]:
graph[u].append(v)
out_degree[u] += 1
in_degree[v] += 1

start = None
for v in graph:
if out_degree[v] - in_degree[v] == 1:
start = v
break

if start is None:
start = next(iter(graph))

stack = [start]
path = []

while stack:
v = stack[-1]
if graph[v]:
u = graph[v].pop()
stack.append(u)
else:
path.append(stack.pop())

return path[::-1]

# Test
g = AdvancedGraph()
edges = [(0, 1), (1, 2), (2, 0), (1, 3), (3, 4), (4, 5), (5, 3)]
for u, v in edges:
g.add_directed_edge(u, v)

print("SCCs:", g.tarjan_scc())
print("Is bipartite:", g.is_bipartite())
print("Has Euler path:", g.has_euler_path())

Common Pitfalls

warning

Mixing SCC detection with regular connectivity: SCCs require directed graphs; undirected graphs don't have meaningful SCCs. Use connected components for undirected graphs.

Wrong degree counting for Euler paths: Count actual edges (not vertices). Multi-edges count multiple times. Self-loops count for both in and out degree.

Starting Euler path from wrong vertex: For path with 2 odd-degree vertices, must start from one of them, not arbitrary vertex. Wrong start makes path impossible.

Not building residual graph for flow: Flow algorithms need residual capacities and backward edges. Forgetting backward edges prevents finding optimal flow.

Confusing bipartite with 2-colorability: Not all 2-colorable graphs are valid problem instances; graph structure matters. Verify bipartite property separately.

Topological sorting not on DAG: Tarjan SCC assumes DAG structure; cyclic graphs need different handling. Verify acyclicity first for correct results.

Self-Check

  1. How does Tarjan's algorithm identify SCC root vertices? What is the significance of low-link values?
  2. Why must a bipartite graph have no odd-length cycles? Prove this property.
  3. For network flow, why is max-flow = min-cut true? What does this mean practically?

One Takeaway

info

Advanced graph algorithms solve complex structural problems. Tarjan's SCC algorithm efficiently decomposes directed graphs into strongly connected components in one DFS pass. Bipartite checking via 2-coloring identifies graph structure quickly. Euler paths traverse edges exactly once, useful for routing and circuit problems. Network flow concepts model resource allocation where max-flow equals minimum cut capacity, enabling optimal distribution solutions. Understanding these algorithms unlocks solutions to real-world problems in social networks, transportation, and telecommunications.

References

  • Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press.
  • Tarjan, R. E. (1972). "Depth-first search and linear graph algorithms." SIAM Journal on Computing, 1(2), 146-160.
  • Ford, L. R., & Fulkerson, D. R. (1956). "Maximal flow through a network." Canadian Journal of Mathematics, 8(3), 399-404.