Dijkstra
Dijkstra’s shortest path algorithm problems for weighted graphs with non-negative edge weights.
Problems
Chocolate Journey
Problem Information
- Source: Hackerearth
- Difficulty: Secret
- Time Limit: 2000ms
- Memory Limit: 256MB
Problem Statement
There are N cities connected by M bidirectional roads. K cities have chocolate shops. You need to travel from city A to city B, but must buy chocolate from one of the K cities. The chocolate expires after X time units, so you must reach B within X time from the chocolate city.
Find the minimum time to go from A to a chocolate city and then to B, such that the chocolate city to B takes at most X time.
Input Format
- Line 1: N M K X (cities, roads, chocolate cities, max time for chocolate)
- Line 2: K integers (chocolate city IDs)
- Next M lines: u v w (bidirectional road with weight w)
- Last line: A B (start and destination)
Output Format
Minimum total time, or -1 if impossible.
Example
Input:
4 4 2 3
2 3
1 2 2
2 3 1
3 4 2
1 4 5
1 4
Output:
5
4 cities, chocolate at cities 2 and 3. Max chocolate freshness time is 3. Path: 1->2 (2) ->3 (1) ->4 (2). Total time = 5. City 3 to 4 takes 2 <= 3, so chocolate stays fresh.
Solution
Approach
Run Dijkstra from A and from B. For each chocolate city within X distance from B, calculate total path through that city.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(n, start, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
n, m, k, x = (int(tokens.pop()) for _ in range(4))
chocolate_cities = [int(tokens.pop()) for _ in range(k)]
graph = defaultdict(list)
for _ in range(m):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph[a].append((b, w))
graph[b].append((a, w))
start, end = int(tokens.pop()), int(tokens.pop())
dist_from_end = dijkstra(n, end, graph)
dist_from_start = dijkstra(n, start, graph)
# Find minimum time through a valid chocolate city
min_time = -1
for city in chocolate_cities:
if 0 <= dist_from_end[city] <= x and dist_from_start[city] >= 0:
total = dist_from_start[city] + dist_from_end[city]
if min_time == -1 or total < min_time:
min_time = total
print(min_time)
solution()
Complexity Analysis
- Time Complexity: O((N + M) log N) for two Dijkstra runs
- Space Complexity: O(N + M) for graph and distance arrays
Commandos
Problem Information
- Source: LightOJ 1174
- Difficulty: Secret
- Time Limit: 2000ms
- Memory Limit: 32MB
Problem Statement
A group of commandos starts at building S. They must visit ALL N buildings to complete their mission, then gather at building D. All commandos move simultaneously and take optimal paths.
The total time is determined by the last commando to reach D. Find the minimum time for all commandos to complete the mission.
Input Format
- Line 1: T (test cases)
- For each test case:
- Line 1: N (buildings)
- Line 2: R (roads)
- Next R lines: u v (bidirectional road)
- Last line: S D (start and destination buildings)
Output Format
Maximum of (dist[S][i] + dist[i][D]) for all buildings i.
Example
Input:
1
4
4
0 1
1 2
2 3
0 2
0 3
Output:
Case 1: 4
4 buildings. Commandos start at 0, gather at 3. Building 1 takes: 0->1 (1 step) + 1->2->3 (2 steps) = 3. Building 2 takes: 0->2 (1 step) + 2->3 (1 step) = 2. Building 0 takes 0 + 0->2->3 = 2. The slowest is going via 1 then to 3 via 2, taking max = 4 (corrected path 0->1->2->3 = 3 and back needs 1 more).
Solution
Approach
Run Dijkstra from S and from D, find max sum for any building to get the time of the slowest commando.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(n, start, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
t = int(tokens.pop())
results = []
for case_num in range(1, t + 1):
n, r = int(tokens.pop()), int(tokens.pop())
graph = defaultdict(list)
for _ in range(r):
a, b = int(tokens.pop()), int(tokens.pop())
graph[a].append((b, 1))
graph[b].append((a, 1))
s, d = int(tokens.pop()), int(tokens.pop())
dist_from_s = dijkstra(n, s, graph)
dist_from_d = dijkstra(n, d, graph)
max_time = max(dist_from_s[j] + dist_from_d[j] for j in range(n))
results.append(f"Case {case_num}: {max_time}")
print(*results, sep='\n')
solution()
Complexity Analysis
- Time Complexity: O(N * (N + R) log N) for N Dijkstra runs
- Space Complexity: O(N + R) for graph storage
MICEMAZE - Mice and Maze
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1129ms
- Memory Limit: 1536MB
Problem Statement
N mice are in a maze with N cells. Cell E is the exit. Each mouse starts in a different cell and has T seconds to reach the exit. Passages are one-way with travel times.
Count how many mice can reach the exit within the time limit.
Input Format
- Line 1: N (cells/mice)
- Line 2: E (exit cell)
- Line 3: T (time limit)
- Line 4: M (number of passages)
- Next M lines: A B W (one-way passage from A to B taking W time)
Output Format
Number of mice that can reach exit in time.
Example
Input:
4
2
1
3
1 2 1
Output:
2
4 cells, exit at cell 2, time limit 1, one passage from 1 to 2 taking 1 second. Mouse at cell 2: distance 0 <= 1. Mouse at cell 1 can reach via passage in 1 second. Mice at cells 3 and 4 cannot reach. Answer: 2 mice.
Solution
Approach
Run Dijkstra from exit on REVERSED graph. Count cells whose distance is within T.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(start, n, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
n = int(tokens.pop())
exit_cell = int(tokens.pop())
time_limit = int(tokens.pop())
m = int(tokens.pop())
# Build reversed graph (from destination to sources)
graph = defaultdict(list)
for _ in range(m):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph[b].append((a, w))
dist = dijkstra(exit_cell, n, graph)
# Count mice that can reach exit within time limit
result = sum(1 for i in range(1, n + 1) if 0 <= dist[i] <= time_limit)
print(result)
solution()
Complexity Analysis
- Time Complexity: O((N + M) log N) for Dijkstra
- Space Complexity: O(N + M) for graph and distance arrays
SHPATH - The Shortest Path
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1537ms
- Memory Limit: 1536MB
Problem Statement
Given a weighted directed graph where cities have names, answer multiple shortest path queries between pairs of cities.
Input Format
- Line 1: S (number of test cases)
- For each test case:
- Line 1: N (number of cities)
- For each city:
- City name
- Number of neighbors, followed by (neighbor_id, cost) pairs
- Line: R (number of queries)
- Next R lines: source_name destination_name
Output Format
Shortest path distance for each query.
Example
Input:
1
3
Bratislava
2
2 2
3 5
Vienna
1
3 3
Prague
0
2
Bratislava Vienna
Vienna Prague
Output:
2
3
3 cities. Bratislava connects to Vienna (cost 2), Prague (cost 5). Vienna connects to Prague (cost 3). Query 1: Bratislava to Vienna = 2. Query 2: Vienna to Prague = 3.
Solution
Approach
Dijkstra from source to destination for each query using city name to index mapping.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
def dijkstra(n, start, dest, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist[dest]
def solution():
num_cases = int(input())
for _ in range(num_cases):
line = input().strip()
n = int(line) if line else int(input())
city_to_idx = {}
graph = defaultdict(list)
for city_idx in range(1, n + 1):
city_name = input().strip()
city_to_idx[city_name] = city_idx
num_roads = int(input())
for _ in range(num_roads):
neighbor, weight = map(int, input().split())
graph[city_idx].append((neighbor, weight))
num_queries = int(input())
for _ in range(num_queries):
src, dst = input().split()
print(dijkstra(n, city_to_idx[src], city_to_idx[dst], graph))
solution()
Complexity Analysis
- Time Complexity: O(R * (N + M) log N) for R queries
- Space Complexity: O(N + M) for graph storage
TRAFFICN - Traffic Network
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 211ms
- Memory Limit: 1536MB
Problem Statement
A city has N junctions connected by M one-way roads. The mayor can build ONE new bidirectional road from a list of K proposals. Find the minimum shortest path from junction S to T after optimally choosing which new road to build (or not building any).
Input Format
- Line 1: T (test cases)
- For each test case:
- Line 1: N M K S T
- Next M lines: u v w (existing one-way road)
- Next K lines: u v w (proposed bidirectional road)
Output Format
Minimum shortest path S to T, or -1 if unreachable.
Example
Input:
1
4 2 1 1 4
1 2 5
3 4 5
2 3 1
Output:
11
4 junctions, 2 existing roads (1->2 cost 5, 3->4 cost 5). One proposed bidirectional road 2-3 cost 1. Best path: 1->2->3->4 = 5+1+5 = 11.
Solution
Approach
Run Dijkstra from S on original graph and from T on reversed graph. Try each proposed road in both directions.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(n, start, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
num_tests = int(tokens.pop())
for _ in range(num_tests):
n, m, k, s, t = (int(tokens.pop()) for _ in range(5))
graph = defaultdict(list)
rev_graph = defaultdict(list)
existing = {}
for _ in range(m):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
existing[(a, b)] = w
graph[a].append((b, w))
rev_graph[b].append((a, w))
proposed = [(int(tokens.pop()), int(tokens.pop()), int(tokens.pop())) for _ in range(k)]
dist_from_s = dijkstra(n, s, graph)
dist_from_t = dijkstra(n, t, rev_graph)
min_path = dist_from_s[t] if dist_from_s[t] > 0 else -1
for u, v, w in proposed:
# Check if existing edge is shorter
edge_weight = min(w, existing.get((u, v), w))
# Try u -> v direction
if dist_from_s[u] >= 0 and dist_from_t[v] >= 0:
path = dist_from_s[u] + edge_weight + dist_from_t[v]
if min_path == -1 or path < min_path:
min_path = path
# Try v -> u direction (bidirectional proposed road)
if dist_from_s[v] >= 0 and dist_from_t[u] >= 0:
path = dist_from_s[v] + edge_weight + dist_from_t[u]
if min_path == -1 or path < min_path:
min_path = path
print(min_path)
solution()
Complexity Analysis
- Time Complexity: O((N + M) log N + K) for two Dijkstra runs plus K road checks
- Space Complexity: O(N^2) for adjacency matrix, O(N + M) for graphs
TRVCOST - Travelling Cost
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 296ms
- Memory Limit: 1536MB
Problem Statement
Given N bidirectional weighted roads and a starting city U, answer Q queries about the shortest distance from U to various destination cities.
Input Format
- Line 1: N (number of roads)
- Next N lines: A B W (bidirectional road between A and B with cost W)
- Line: U (starting city)
- Line: Q (number of queries)
- Next Q lines: destination city
Output Format
For each query, print shortest distance or “NO PATH”.
Example
Input:
3
1 2 5
2 3 3
1 3 10
1
3
2
3
Output:
8
5
3 roads. Starting city is 1. Query 1: city 3. Shortest path 1->2->3 = 5+3 = 8. Query 2: city 2. Shortest path 1->2 = 5.
Solution
Approach
Single Dijkstra from U, answer all queries from the precomputed distance array.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
MAX = 1100
def dijkstra(start, graph):
dist = [-1] * MAX
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
n = int(tokens.pop())
graph = defaultdict(list)
for _ in range(n):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph[a].append((b, w))
graph[b].append((a, w))
start = int(tokens.pop())
q = int(tokens.pop())
queries = [int(tokens.pop()) for _ in range(q)]
dist = dijkstra(start, graph)
results = [str(dist[dest]) if dist[dest] != -1 else 'NO PATH' for dest in queries]
print(*results, sep='\n')
solution()
Complexity Analysis
- Time Complexity: O((V + N) log V + Q) where V is max vertex
- Space Complexity: O(V + N) for graph and distance arrays
Sending Email
Problem Information
- Source: UVA 10986
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Given a network of N servers connected by M bidirectional cables with latencies, find the minimum latency to send an email from server S to server T.
Input Format
- Line 1: N (test cases)
- For each test case:
- Line 1: n m S T (servers, cables, source, target)
- Next m lines: A B W (cable between A and B with latency W)
Output Format
“Case #X: Y” where Y is shortest distance, or “unreachable”.
Example
Input:
2
4 3 0 3
0 1 2
1 2 3
2 3 1
3 2 0 2
0 1 5
Output:
Case #1: 6
Case #2: unreachable
Case 1: 4 servers, path 0->1->2->3 = 2+3+1 = 6. Case 2: No path from 0 to 2.
Solution
Approach
Standard Dijkstra’s algorithm from S to T.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(n, start, dest, graph):
dist = [-1] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist[dest] if dist[dest] >= 0 else None
def solution():
tokens = sys.stdin.read().split()[::-1]
num_cases = int(tokens.pop())
results = []
for case_num in range(1, num_cases + 1):
n, m, s, t = (int(tokens.pop()) for _ in range(4))
graph = defaultdict(list)
for _ in range(m):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph[a].append((b, w))
graph[b].append((a, w))
dist = dijkstra(n, s, t, graph)
result = str(dist) if dist is not None else 'unreachable'
results.append(f"Case #{case_num}: {result}")
print(*results, sep='\n')
solution()
Complexity Analysis
- Time Complexity: O((n + m) log n) per test case
- Space Complexity: O(n + m) for graph storage
Almost Shortest Path
Problem Information
- Source: UVA 12144
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Find the “almost shortest path” from S to D. This is the shortest path that does NOT use any edge that appears in ANY shortest path from S to D.
Input Format
- Multiple test cases until n=0 m=0
- For each test case:
- Line 1: n m (nodes, edges)
- Line 2: S D (source, destination)
- Next m lines: A B W (directed edge from A to B with weight W)
Output Format
Almost shortest path length, or -1 if impossible.
Example
Input:
4 5
0 3
0 1 1
1 3 1
0 2 2
2 3 1
1 2 1
0 0
Output:
3
Shortest path 0->1->3 has length 2. The “almost shortest” avoids edges on this path. Path 0->2->3 = 2+1 = 3.
Solution
Approach
Run Dijkstra from S and reverse Dijkstra from D. Identify edges on shortest paths where dist_S[u] + w + dist_D[v] == shortest, remove them, run Dijkstra again.
Python Solution
from heapq import heappush, heappop
from collections import defaultdict
import sys
def dijkstra(n, start, graph, blocked):
dist = [-1] * n
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heappop(pq)
for v, w in graph[u]:
if (u, v) not in blocked:
new_dist = d + w
if dist[v] == -1 or new_dist < dist[v]:
dist[v] = new_dist
heappush(pq, (new_dist, v))
return dist
def solution():
tokens = sys.stdin.read().split()[::-1]
while True:
n = int(tokens.pop())
if n == 0:
break
m, s, d = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph = defaultdict(list)
rev_graph = defaultdict(list)
for _ in range(m):
a, b, w = int(tokens.pop()), int(tokens.pop()), int(tokens.pop())
graph[a].append((b, w))
rev_graph[b].append((a, w))
dist_from_s = dijkstra(n, s, graph, set())
dist_from_d = dijkstra(n, d, rev_graph, set())
shortest = dist_from_s[d]
if shortest == -1:
print(-1)
continue
# Find and block edges on any shortest path
blocked = set()
for u in range(n):
for v, w in graph[u]:
if (dist_from_s[u] >= 0 and dist_from_d[v] >= 0 and
dist_from_s[u] + w + dist_from_d[v] == shortest):
blocked.add((u, v))
almost_shortest = dijkstra(n, s, graph, blocked)[d]
print(almost_shortest)
solution()
Complexity Analysis
- Time Complexity: O((n + m) log n) for multiple Dijkstra runs
- Space Complexity: O(n^2) for adjacency matrix