Strongly Connected Edges
Problem Overview
| Attribute | Value |
|---|---|
| CSES Link | https://cses.fi/problemset/task/2177 |
| Difficulty | Hard |
| Category | Graph Theory |
| Time Limit | 1 second |
| Key Technique | Bridge Finding + DFS Edge Orientation |
Learning Goals
After solving this problem, you will be able to:
- Find bridges in an undirected graph using Tarjan’s algorithm
- Understand when an undirected graph can be oriented to be strongly connected
- Orient edges using DFS tree traversal (tree edges down, back edges up)
- Apply low-link values to detect bridges
Problem Statement
Problem: Given an undirected graph, orient each edge to create a directed graph that is strongly connected. If impossible, print “IMPOSSIBLE”.
Input:
- Line 1: Two integers n and m (number of nodes and edges)
- Next m lines: Two integers a and b (undirected edge between a and b)
Output:
- If possible: m lines, each with directed edge “a b” meaning edge from a to b
- If impossible: “IMPOSSIBLE”
Constraints:
- 1 <= n <= 10^5
- 1 <= m <= 2 x 10^5
- Graph is connected
Example
Input:
3 3
1 2
1 3
2 3
Output:
1 2
3 1
2 3
Explanation: The triangle can be oriented as a cycle: 1->2->3->1. Every node can reach every other node.
Intuition: How to Think About This Problem
Pattern Recognition
Key Question: When can we orient an undirected graph to make it strongly connected?
The answer lies in bridges. A bridge is an edge whose removal disconnects the graph. If we orient a bridge edge, one side can never reach the other.
Breaking Down the Problem
- What are we looking for? Direction for each edge so all nodes can reach all other nodes.
- What makes it impossible? If there is a bridge, we cannot make it strongly connected.
- How do we orient? Use DFS - tree edges go down (parent to child), back edges go up (descendant to ancestor).
The Key Insight
A graph can be oriented to be strongly connected
if and only if
it has NO BRIDGES (is 2-edge-connected)
Why DFS Orientation Works
When we run DFS on a graph with no bridges:
- Tree edges: Orient from parent to child (going down)
- Back edges: Orient from descendant to ancestor (going up)
This creates cycles because every tree edge is “covered” by some back edge (no bridges means every tree edge has a back edge that bypasses it).
Solution: Bridge Detection + DFS Orientation
Algorithm Overview
- Run DFS to find all bridges using low-link values
- If any bridge exists, output “IMPOSSIBLE”
- Otherwise, orient edges: tree edges go down, back edges go up
Understanding Low-Link Values
disc[u] = Discovery time of node u
low[u] = Minimum discovery time reachable from subtree of u
(using one back edge)
Bridge condition: For edge (u, v) where u is parent of v,
if low[v] > disc[u], then (u,v) is a bridge
Visual Example
Graph: DFS Tree: Oriented:
1---2 1 1-->2
|\ /| | | |
| X | 2 v v
|/ \| | 3<--+
3---4 3 | |
| v v
4 4<--+
Back edges: 1-3, 2-3, 2-4, 3-4 (all go UP in DFS tree)
Result: Every node reachable from every other node
Dry Run Example
Let’s trace through with the triangle graph (n=3, m=3):
Graph: 1-2, 1-3, 2-3
DFS from node 1:
-----------------
Visit 1: disc[1]=0, low[1]=0
-> Explore edge 1-2 (tree edge)
Visit 2: disc[2]=1, low[2]=1
-> Explore edge 2-3 (tree edge)
Visit 3: disc[3]=2, low[3]=2
-> Explore edge 3-1 (back edge to ancestor)
Update: low[3] = min(low[3], disc[1]) = 0
-> Edge 3-2 is to parent, skip
Return to 2: low[2] = min(low[2], low[3]) = 0
-> Edge 2-1 is to parent, skip
Return to 1: low[1] = min(low[1], low[2]) = 0
Bridge check for each tree edge:
Edge 1-2: low[2]=0, disc[1]=0, low[2] <= disc[1] -> NOT a bridge
Edge 2-3: low[3]=0, disc[2]=1, low[3] <= disc[2] -> NOT a bridge
No bridges! Can orient successfully.
Edge orientations:
1-2: Tree edge, orient as 1->2
2-3: Tree edge, orient as 2->3
1-3: Back edge from 3 to 1, orient as 3->1
Result: 1->2, 2->3, 3->1 (forms a cycle!)
Code (Python)
import sys
from collections import defaultdict
sys.setrecursionlimit(300000)
def solve():
input_data = sys.stdin.read().split()
idx = 0
n = int(input_data[idx]); idx += 1
m = int(input_data[idx]); idx += 1
# Build adjacency list with edge indices
adj = defaultdict(list)
edges = []
for i in range(m):
a = int(input_data[idx]); idx += 1
b = int(input_data[idx]); idx += 1
adj[a].append((b, i))
adj[b].append((a, i))
edges.append([a, b])
# DFS arrays
disc = [0] * (n + 1)
low = [0] * (n + 1)
visited = [False] * (n + 1)
timer = [1]
has_bridge = [False]
# Result: direction[i] = True means edge[i] keeps original direction
direction = [True] * m
def dfs(u, parent_edge_idx):
visited[u] = True
disc[u] = low[u] = timer[0]
timer[0] += 1
for v, edge_idx in adj[u]:
if edge_idx == parent_edge_idx:
continue
if visited[v]:
# Back edge: orient toward ancestor (v has smaller disc)
low[u] = min(low[u], disc[v])
if disc[v] < disc[u]:
# v is ancestor, orient u -> v
if edges[edge_idx][0] == u:
direction[edge_idx] = True # u->v
else:
direction[edge_idx] = False # flip to u->v
else:
# Tree edge: orient toward child (u -> v)
if edges[edge_idx][0] == u:
direction[edge_idx] = True
else:
direction[edge_idx] = False
dfs(v, edge_idx)
low[u] = min(low[u], low[v])
# Check for bridge
if low[v] > disc[u]:
has_bridge[0] = True
# Run DFS from node 1
dfs(1, -1)
if has_bridge[0]:
print("IMPOSSIBLE")
return
# Output oriented edges
result = []
for i in range(m):
a, b = edges[i]
if direction[i]:
result.append(f"{a} {b}")
else:
result.append(f"{b} {a}")
print('\n'.join(result))
solve()
Complexity Analysis
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n + m) | Single DFS traversal |
| Space | O(n + m) | Adjacency list and DFS arrays |
Common Mistakes
Mistake 1: Not Handling Multi-edges Correctly
Problem: If there are multiple edges between same nodes, skipping by parent node skips all of them. Fix: Track and skip by edge index, not by node.
Mistake 2: Wrong Bridge Condition
Problem: >= detects articulation points, not bridges.
Fix: Use strict inequality > for bridge detection.
Mistake 3: Forgetting Back Edge Orientation
Edge Cases
| Case | Input | Expected Output | Why |
|---|---|---|---|
| Single edge | n=2, edge: 1-2 | IMPOSSIBLE | Single edge is always a bridge |
| Triangle | n=3, edges: triangle | Valid orientation | No bridges, forms cycle |
| Two triangles sharing edge | n=4, 5 edges | Valid orientation | 2-edge-connected |
| Path graph | n=3, edges: 1-2, 2-3 | IMPOSSIBLE | All edges are bridges |
| Complete graph | K_n | Valid orientation | Highly connected |
When to Use This Pattern
Use This Approach When:
- Need to orient edges to achieve strong connectivity
- Need to detect bridges (critical edges) in undirected graphs
- Working with 2-edge-connectivity problems
Pattern Recognition Checklist:
- Given undirected graph, need to direct edges? -> Consider DFS orientation
- Need strong connectivity? -> Check for bridges first
- Bridges = impossible? -> Use low-link bridge detection
Related Concepts:
- Bridges: Edges whose removal disconnects graph
- 2-edge-connected: Graph with no bridges
- DFS Tree: Tree edges (going down) vs back edges (going up)
Related Problems
Easier (Do These First)
| Problem | Why It Helps |
|---|---|
| Building Roads | Basic connectivity |
| Finding Bridges | Bridge detection practice |
Similar Difficulty
| Problem | Key Difference |
|---|---|
| Critical Connections | Only find bridges, no orientation |
| Flight Routes Check | Check if directed graph is strongly connected |
Harder (Do These After)
| Problem | New Concept |
|---|---|
| Planets and Kingdoms | SCC decomposition |
| Coin Collector | DP on SCC DAG |
Key Takeaways
-
The Core Idea: A graph can be oriented to be strongly connected if and only if it has no bridges.
-
Bridge Detection: Use low-link values - edge (u,v) is bridge if
low[v] > disc[u]where u is parent of v. -
Orientation Rule: Tree edges go down (parent to child), back edges go up (descendant to ancestor).
-
Why It Works: No bridges means every tree edge has a bypassing back edge, creating cycles that enable bidirectional reachability.
Practice Checklist
Before moving on, make sure you can:
- Implement bridge finding with low-link values
- Explain why bridges make strong connectivity impossible
- Orient a graph using DFS tree structure
- Handle multi-edges correctly using edge indices
Additional Resources
- CP-Algorithms: Bridge Finding
- CP-Algorithms: Strongly Connected Components
- CSES Strongly Connected Edges - Make graph strongly connected