Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Find the number of distinct pairs of vertices which have a distance of exactly k in a tree in Python
Finding the number of distinct pairs of vertices with exactly distance k in a tree is a classic dynamic programming problem. We use DFS traversal with memoization to count paths of specific lengths from each node.
Problem Understanding
Given a tree with n nodes and an integer k, we need to count all distinct pairs of vertices that are exactly k edges apart. For the tree shown below with k = 2:
Algorithm Approach
We use dynamic programming with DFS where vertex_count[v][d] stores the number of vertices at exactly distance d from vertex v in its subtree.
Implementation
def count_pairs_at_distance_k(edges, k, n):
"""Count pairs of vertices with exactly distance k in a tree"""
# Build adjacency list
graph = [[] for _ in range(n + 1)]
for x, y in edges:
graph[x].append(y)
graph[y].append(x)
# vertex_count[v][d] = number of vertices at distance d from v in its subtree
vertex_count = [[0 for _ in range(k + 1)] for _ in range(n + 1)]
result = 0
def dfs(v, parent):
nonlocal result
vertex_count[v][0] = 1 # The vertex itself at distance 0
for neighbor in graph[v]:
if neighbor != parent:
dfs(neighbor, v)
# Count pairs where one vertex is in current subtree and other in neighbor's subtree
for dist in range(1, k + 1):
result += vertex_count[neighbor][dist - 1] * vertex_count[v][k - dist]
# Update vertex counts for current vertex
for dist in range(1, k + 1):
vertex_count[v][dist] += vertex_count[neighbor][dist - 1]
dfs(1, 0)
return result
# Example usage
edges = [(1, 2), (2, 3), (3, 4), (2, 5)]
k = 2
n = 5
result = count_pairs_at_distance_k(edges, k, n)
print(f"Number of pairs with distance {k}: {result}")
Number of pairs with distance 2: 4
How It Works
The algorithm performs these key steps:
- DFS Traversal: Visit each vertex and process its subtrees
- Pair Counting: For each vertex, count pairs where one endpoint is in the current subtree and the other is in a child's subtree
- Dynamic Programming: Store counts of vertices at each distance to avoid recalculation
Step-by-Step Example
def count_pairs_detailed(edges, k, n):
graph = [[] for _ in range(n + 1)]
for x, y in edges:
graph[x].append(y)
graph[y].append(x)
vertex_count = [[0 for _ in range(k + 1)] for _ in range(n + 1)]
pairs = []
def dfs(v, parent, path=[]):
vertex_count[v][0] = 1
current_path = path + [v]
print(f"Processing vertex {v}, path: {current_path}")
for neighbor in graph[v]:
if neighbor != parent:
dfs(neighbor, v, current_path)
# Find pairs at distance k
for dist in range(1, k + 1):
count = vertex_count[neighbor][dist - 1] * vertex_count[v][k - dist]
if count > 0:
print(f" Found {count} pair(s) with distance {k}")
for dist in range(1, k + 1):
vertex_count[v][dist] += vertex_count[neighbor][dist - 1]
dfs(1, 0)
return sum(vertex_count[1])
# Run detailed example
edges = [(1, 2), (2, 3), (3, 4), (2, 5)]
count_pairs_detailed(edges, 2, 5)
Processing vertex 1, path: [1] Processing vertex 2, path: [1, 2] Processing vertex 3, path: [1, 2, 3] Processing vertex 4, path: [1, 2, 3, 4] Found 1 pair(s) with distance 2 Processing vertex 5, path: [1, 2, 5] Found 2 pair(s) with distance 2 Found 1 pair(s) with distance 2
Time Complexity
The time complexity is O(n × k) where n is the number of vertices and k is the target distance. Space complexity is O(n × k) for the memoization table.
Conclusion
This dynamic programming approach efficiently counts vertex pairs at exactly distance k using DFS traversal and memoization. The algorithm processes each vertex once and maintains distance counts for optimal performance.
