Prim
This session covers Prim’s algorithm for finding Minimum Spanning Trees (MST) in weighted undirected graphs.
Problems
Efficient Network
Problem Information
- Source: Hackerearth
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 256MB
Problem Statement
Build an efficient network connecting N nodes using M weighted edges. Additionally, you have Q “free” connections with costs C[i] that can replace the most expensive edges in the MST to minimize total cost.
Input Format
- First line: N (nodes), M (edges)
- Next M lines: A, B, W (edge from A to B with weight W)
- Next line: Q (number of free connections)
- Next line: Q space-separated costs C[i]
Output Format
Minimum total cost to connect all nodes.
Example
Input:
4 5
1 2 10
2 3 5
3 4 8
1 4 12
2 4 6
2
3 4
Output:
18
MST edges: 2-3 (5), 2-4 (6), 1-2 (10) = 21. Free connections [3,4] sorted. Replace edge 10 with 3, replace edge 6 with 4. New total = 5 + 4 + 3 + 6 = 18.
Solution
Approach
Use Prim’s algorithm with priority queue to find MST. Sort MST edge weights and free connection costs. Greedily replace expensive MST edges with cheaper free connections.
Python Solution
import heapq
def prim(N, graph, C):
dist = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)] # (distance, node) - tuples work with heapq
dist[1] = 0
while pqueue:
d, u = heapq.heappop(pqueue)
visited[u] = True
for v, w in graph[u]:
if not visited[v] and (dist[v] == -1 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
dist.sort()
C.sort()
for i, c in enumerate(C):
if i > N + 1 or dist[-i - 1] <= c:
break
dist[-i - 1] = c
return sum(d for d in dist[1:N + 1] if d != -1)
def solution():
N, M = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for _ in range(M):
A, B, W = map(int, input().split())
graph[A].append((B, W))
graph[B].append((A, W))
Q = int(input())
C = list(map(int, input().strip().split())) if Q > 0 else []
print(prim(N, graph, C))
solution()
Complexity Analysis
- Time Complexity: O(E log V) for Prim’s algorithm + O(Q log Q) for sorting free connections
- Space Complexity: O(V + E) for graph storage
Prim’s MST: Special Subtree
Problem Information
- Source: Hackerrank
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 256MB
Problem Statement
Given an undirected weighted graph, find the weight of the Minimum Spanning Tree (MST). The MST connects all nodes with minimum total edge weight without forming cycles.
Input Format
- First line: N (nodes), M (edges)
- Next M lines: A, B, W (edge between nodes A and B with weight W)
Output Format
Single integer: total weight of the MST.
Example
Input:
5 6
1 2 3
1 3 4
2 3 2
2 4 6
3 4 1
4 5 5
Output:
11
MST edges: 3-4 (1), 2-3 (2), 1-2 (3), 4-5 (5). Total weight = 1 + 2 + 3 + 5 = 11.
Solution
Approach
Prim’s algorithm using a min-heap (priority queue). Start from node 1, greedily add minimum weight edges. Track visited nodes to avoid cycles.
Python Solution
import heapq
def prim(N, graph):
dist = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)] # (distance, node)
dist[1] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v, w in graph[u]:
if not visited[v] and (dist[v] == -1 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
return sum(d for d in dist[1:N + 1] if d != -1)
def solution():
N, M = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for _ in range(M):
A, B, W = map(int, input().split())
graph[A].append((B, W))
graph[B].append((A, W))
print(prim(N, graph))
solution()
Complexity Analysis
- Time Complexity: O(E log V)
- Space Complexity: O(V + E)
Road Construction
Problem Information
- Source: LightOJ
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 32MB
Problem Statement
Given pairs of cities with road construction costs, find the minimum cost to connect all cities. Cities are given by name (strings). If it’s impossible to connect all cities, output “Impossible”.
Input Format
- First line: T (test cases)
- For each test case:
- Blank line
- M (number of roads)
- M lines: city1 city2 cost (road between cities with construction cost)
Output Format
For each test case: “Case X: cost” or “Case X: Impossible”
Example
Input:
2
3
Dhaka Sylhet 100
Sylhet Chittagong 150
Chittagong Dhaka 200
2
Tokyo Osaka 50
Output:
Case 1: 250
Case 2: 50
Case 1: MST connects all 3 cities with edges Dhaka-Sylhet (100) and Sylhet-Chittagong (150) = 250. Case 2: Only 2 cities with one road, MST = 50.
Solution
Approach
Map city names to indices using dictionary. Apply Prim’s algorithm with priority queue. Handle disconnected components (return “Impossible”).
Python Solution
import heapq
def prim(N, graph):
dist = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)]
dist[1] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v, w in graph[u]:
if not visited[v] and (dist[v] == -1 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
for i in range(1, N + 1):
if dist[i] == -1:
return 'Impossible'
return str(sum(d for d in dist[1:N + 1] if d != -1))
def solution():
t = int(input())
for j in range(t):
input()
m = int(input())
graph = [[] for _ in range(m * 2 + 1)]
cities = {}
for _ in range(m):
city1, city2, cost = input().strip().split()
cost = int(cost)
if city1 not in cities:
cities[city1] = len(cities) + 1
if city2 not in cities:
cities[city2] = len(cities) + 1
graph[cities[city1]].append((cities[city2], cost))
graph[cities[city2]].append((cities[city1], cost))
print(f"Case {j + 1}: {prim(len(cities), graph)}")
solution()
Complexity Analysis
- Time Complexity: O(E log V)
- Space Complexity: O(V + E)
Cobbled Streets
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 1536MB
Problem Statement
A town needs to pave roads between junctions. The cost per meter is p, and you’re given road lengths. Find the minimum total cost to connect all junctions so everyone can reach everyone else.
Input Format
- First line: T (test cases)
- For each test case:
- p (cost per meter)
- n (number of junctions)
- m (number of possible roads)
- m lines: a, b, c (road from junction a to b with length c)
Output Format
For each test case: minimum total cost (MST weight * p)
Example
Input:
1
2
4
5
1 2 3
1 3 4
2 3 5
2 4 6
3 4 2
Output:
18
Cost per meter = 2. MST edges: 3-4 (2), 1-2 (3), 1-3 (4). Total length = 9. Cost = 9 * 2 = 18.
Solution
Approach
Use Prim’s algorithm to find MST. Multiply MST total edge weight by price per meter p.
Python Solution
import heapq
def prim(N, graph):
dist = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)]
dist[1] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v, w in graph[u]:
if not visited[v] and (dist[v] == -1 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
return sum(d for d in dist[1:N + 1] if d != -1)
def solution():
t = int(input())
for _ in range(t):
p = int(input())
n = int(input())
m = int(input())
graph = [[] for _ in range(n + 1)]
for _ in range(m):
a, b, c = map(int, input().strip().split())
graph[a].append((b, c))
graph[b].append((a, c))
print(prim(n, graph) * p)
solution()
Complexity Analysis
- Time Complexity: O(E log V)
- Space Complexity: O(V + E)
Minimum Spanning Tree
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 1536MB
Problem Statement
Given an undirected weighted graph, find the total weight of its Minimum Spanning Tree. Classic MST problem.
Input Format
- First line: N (nodes), M (edges)
- Next M lines: A, B, W (edge between A and B with weight W)
Output Format
Single integer: total weight of the MST.
Example
Input:
4 5
1 2 1
1 3 2
2 3 3
2 4 4
3 4 5
Output:
7
MST edges: 1-2 (1), 1-3 (2), 2-4 (4). Total = 1 + 2 + 4 = 7.
Solution
Approach
Standard Prim’s algorithm implementation. Use min-heap priority queue for efficient minimum edge selection. Maintain visited array to avoid cycles.
Python Solution
import heapq
def prim(N, graph):
dist = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)]
dist[1] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v, w in graph[u]:
if not visited[v] and (dist[v] == -1 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
return sum(d for d in dist[1:N + 1] if d != -1)
def solution():
N, M = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for _ in range(M):
A, B, W = map(int, input().split())
graph[A].append((B, W))
graph[B].append((A, W))
print(prim(N, graph))
solution()
Complexity Analysis
- Time Complexity: O(E log V)
- Space Complexity: O(V + E)
Audiophobia
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 512MB
Problem Statement
In a city with crossings connected by streets, each street has a noise level. For multiple queries, find the path between two crossings that minimizes the maximum noise level encountered (minimax path problem).
Input Format
- Multiple test cases until C=S=Q=0
- C (crossings), S (streets), Q (queries)
- S lines: crossing1, crossing2, noise_level
- Q lines: source, destination (query pairs)
Output Format
For each query: minimum possible maximum noise level, or “no path”
Example
Input:
4 4 2
1 2 50
2 3 30
3 4 40
1 4 100
1 4
2 4
0 0 0
Output:
Case #1
50
40
Query 1-4: Path 1-2-3-4 has max noise 50, path 1-4 has noise 100. Minimax = 50. Query 2-4: Path 2-3-4 has max noise 40, which is the minimax path.
Solution
Approach
Modified Floyd-Warshall algorithm. Instead of summing distances, take minimum of maximum edge weights: graph[i][j] = min(graph[i][j], max(graph[i][k], graph[k][j]))
Python Solution
INF = 1e9
def solution():
case_num = 0
while True:
C, S, Q = map(int, input().strip().split())
if C == 0:
break
if case_num > 0:
print()
graph = [[INF] * (C + 1) for _ in range(C + 1)]
for _ in range(S):
A, B, W = map(int, input().strip().split())
graph[A][B] = graph[B][A] = min(graph[A][B], W)
# Floyd-Warshall for minimax path
for k in range(1, C + 1):
for i in range(1, C + 1):
for j in range(1, C + 1):
graph[i][j] = min(graph[i][j], max(graph[i][k], graph[k][j]))
case_num += 1
print(f"Case #{case_num}")
for _ in range(Q):
s, e = map(int, input().strip().split())
print('no path' if graph[s][e] == INF else int(graph[s][e]))
solution()
Complexity Analysis
- Time Complexity: O(V^3) for Floyd-Warshall
- Space Complexity: O(V^2)
Connect the Campus
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 512MB
Problem Statement
A university campus has n buildings at (x, y) coordinates. Some buildings are already connected by existing cables. Find the minimum additional cable length needed to connect all buildings (Euclidean distances).
Input Format
- n (number of buildings)
- n lines: x, y coordinates of each building
- m (number of existing connections)
- m lines: pairs of already connected buildings
Output Format
Minimum cable length needed (2 decimal places).
Example
Input:
4
0 0
0 10
10 0
10 10
1
1 2
Output:
20.00
Building 1 and 2 are already connected (cost 0). Need cables: 1-3 (distance 10) and 3-4 (distance 10). Total new cable = 20.00.
Solution
Approach
Create complete graph with Euclidean distances between all buildings. Set existing connections to weight 0. Apply Prim’s algorithm to find MST. Sum only non-zero edges (new cables needed).
Python Solution
import math
import heapq
import sys
class InputTokenizer:
def __init__(self):
self._tokens = sys.stdin.read().split()[::-1]
def has_next(self):
return bool(self._tokens)
def next(self):
return self._tokens.pop()
inp = InputTokenizer()
def prim(N, graph):
dist = [-1.0] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0.0, 0)]
dist[0] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v in range(N):
w = graph[u][v]
if not visited[v] and w != -1 and (dist[v] == -1.0 or w < dist[v]):
dist[v] = w
heapq.heappush(pqueue, (w, v))
return sum(d for d in dist[:N] if d != -1.0)
def solution():
while inp.has_next():
n = int(inp.next())
cities = [(int(inp.next()), int(inp.next())) for _ in range(n)]
graph = [[-1.0] * (n + 1) for _ in range(n + 1)]
for i in range(n):
for j in range(i + 1, n):
d = math.hypot(cities[i][0] - cities[j][0], cities[i][1] - cities[j][1])
graph[i][j] = graph[j][i] = d
m = int(inp.next())
for _ in range(m):
x, y = int(inp.next()) - 1, int(inp.next()) - 1
graph[x][y] = graph[y][x] = 0
print(f"{prim(n, graph):.2f}")
solution()
Complexity Analysis
- Time Complexity: O(V^2 log V) for dense graph with Prim’s
- Space Complexity: O(V^2)
ACM Contest and Blackout
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 512MB
Problem Statement
Find both the Minimum Spanning Tree (MST) and the Second-Best MST for a given graph. The second-best MST differs by exactly one edge from the MST.
Input Format
- T (test cases)
- For each test case:
- N (nodes), M (edges)
- M lines: A, B, C (edge between A and B with weight C)
Output Format
For each test case: two integers - MST weight and second-best MST weight.
Example
Input:
1
4 5
1 2 1
1 3 2
2 3 3
2 4 4
3 4 5
Output:
7 8
MST: 1-2 (1), 1-3 (2), 2-4 (4) = 7. Second-best MST: Remove edge 1-3, use 2-3 instead. Or remove 2-4, use 3-4. Best second MST = 8.
Solution
Approach
First, find the MST using Prim’s algorithm (track the path/edges used). For second-best MST: try removing each MST edge one at a time. Recompute MST without that edge, find minimum among all such trees.
Python Solution
import heapq
def prim(N, graph):
dist = [-1] * (N + 1)
path = [-1] * (N + 1)
visited = [False] * (N + 1)
pqueue = [(0, 1)]
dist[1] = 0
while pqueue:
_, u = heapq.heappop(pqueue)
visited[u] = True
for v in range(1, N + 1):
w = graph[u][v]
if not visited[v] and w != -1 and (dist[v] == -1 or w < dist[v]):
dist[v] = w
path[v] = u
heapq.heappush(pqueue, (w, v))
mst_cost = sum(d for d in dist[1:N + 1] if d != -1)
return path, mst_cost
def solution():
T = int(input())
for _ in range(T):
N, M = map(int, input().strip().split())
graph = [[-1] * (N + 1) for _ in range(N + 1)]
for _ in range(M):
A, B, C = map(int, input().strip().split())
graph[A][B] = graph[B][A] = C
mst, mst_cost = prim(N, graph)
second_mst_cost = int(1e9)
for i, parent in enumerate(mst):
if parent != -1:
tmp_weight = graph[i][parent]
graph[i][parent] = graph[parent][i] = -1
_, current_cost = prim(N, graph)
second_mst_cost = min(second_mst_cost, current_cost)
graph[i][parent] = graph[parent][i] = tmp_weight
print(mst_cost, second_mst_cost)
solution()
Complexity Analysis
- Time Complexity: O(V * E log V) for finding second-best MST
- Space Complexity: O(V^2)