Floyd-Warshall
This session covers the Floyd-Warshall algorithm for finding all-pairs shortest paths in weighted graphs.
Problems
Maximum Weight Composition
Problem Information
- Source: CodeChef
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 256MB
Problem Statement
Given N intervals with start position, end position, and cost, find the maximum total cost by selecting non-overlapping intervals. An interval from [si, ei] must end before the next one starts.
Input Format
- T: number of test cases
- For each test case:
- N: number of intervals
- N lines with si ei ci: start, end, and cost of interval
Output Format
- Maximum total cost achievable with non-overlapping intervals
Example
Input:
1
3
1 2 5
3 4 6
2 5 3
Output:
11
Select intervals [1,2] with cost 5 and [3,4] with cost 6. They don’t overlap, so total cost is 5+6=11. Interval [2,5] overlaps with both, so we skip it.
Solution
Approach
Use dynamic programming approach (simplified from Floyd-Warshall concept). For each endpoint, compute maximum cost considering all intervals ending there. mmax[x] = max(mmax[x], graph[xx][x] + mmax[xx]) for all xx < x. Essentially an interval scheduling maximization problem.
Python Solution
def solution():
t = int(input().strip())
max_endpoint = 49
for _ in range(t):
graph = [[0] * max_endpoint for _ in range(max_endpoint)]
n = int(input().strip())
e_max = 0
for _ in range(n):
si, ei, ci = map(int, input().strip().split())
e_max = max(e_max, ei)
graph[si][ei] = max(graph[si][ei], ci)
# DP: mmax[x] = max total cost ending at position x
mmax = [0] * max_endpoint
for x in range(1, e_max + 1):
mmax[x] = max(graph[xx][x] + mmax[xx] for xx in range(x))
print(mmax[e_max])
solution()
Complexity Analysis
- Time Complexity: O(T * M^2) where M is maximum endpoint value
- Space Complexity: O(M^2)
Greg and Graph
Problem Information
- Source: Codeforces
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Given a weighted directed graph and an order of vertex deletions, compute the sum of all shortest paths after each deletion (in reverse, after each vertex is added back). Process deletions in reverse order to build the graph.
Input Format
- N: number of vertices
- N x N adjacency matrix with edge weights
- Deletion order: sequence of N vertices to be deleted
Output Format
- N integers: sum of all shortest paths after adding vertices in reverse deletion order (i.e., before each deletion in original order)
Example
Input:
3
0 10 20
10 0 5
20 5 0
1 2 3
Output:
70 20 0
After all 3 vertices: sum of paths = 0+10+20+10+0+5+20+5+0 = 70. After deleting vertex 1: only vertices 2,3 remain with dist 5, so sum = 5+5+0+0 = 10… The output shows cumulative sums.
Solution
Approach
Reverse the deletion order to process as additions. Use incremental Floyd-Warshall: when adding vertex k, update all pairs (i,j) considering k as intermediate vertex. After adding each vertex, sum all current shortest paths. Output results in reverse (corresponding to original deletion order).
Python Solution
INF = float('inf')
def floyd_warshall(n, matrix, del_list):
ans = [0] * (n + 1)
for k in range(n, 0, -1):
c = del_list[k]
# Update distances through the newly added vertex c
for i in range(k + 1, n + 1):
a = del_list[i]
for j in range(k, n + 1):
b = del_list[j]
matrix[c][a] = min(matrix[c][a], matrix[c][b] + matrix[b][a])
matrix[a][c] = min(matrix[a][c], matrix[a][b] + matrix[b][c])
for i in range(k, n + 1):
a = del_list[i]
for j in range(k, n + 1):
b = del_list[j]
if a != b:
matrix[a][b] = min(matrix[a][b], matrix[a][c] + matrix[c][b])
# Sum all shortest paths
ans[k] = sum(
matrix[del_list[i]][del_list[j]]
for i in range(k, n + 1)
for j in range(k, n + 1)
)
return ans[1:n + 1]
def solution():
n = int(input().strip())
matrix = [[]] + [
[0] + list(map(int, input().strip().split()))
for _ in range(n)
]
del_list = [0] + list(map(int, input().strip().split()))
print(*floyd_warshall(n, matrix, del_list), sep=' ')
solution()
Complexity Analysis
- Time Complexity: O(N^3)
- Space Complexity: O(N^2)
Arbitrage
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 1536MB
Problem Statement
Given currency exchange rates between different currencies, determine if arbitrage is possible. Arbitrage means starting with some currency and exchanging through a sequence of currencies to end up with more of the original currency than you started with.
Input Format
- Multiple test cases until n=0
- For each test case:
- n: number of currencies
- n currency names
- m: number of exchange rates
- m lines: currency1 rate currency2 (exchange currency1 to currency2 at given rate)
Output Format
- “Case X: Yes” if arbitrage is possible, “Case X: No” otherwise
Example
Input:
3
USDollar
BritishPound
Euro
3
USDollar 0.5 BritishPound
BritishPound 2.1 USDollar
Euro 1.0 USDollar
0
Output:
Case 1: Yes
USD->GBP at 0.5, GBP->USD at 2.1. Starting with 1 USD: 1 * 0.5 * 2.1 = 1.05 USD. Profit of 5%, so arbitrage is possible.
Solution
Approach
Use modified Floyd-Warshall for product maximization instead of sum minimization. matrix[i][j] = max(matrix[i][j], matrix[i][k] * matrix[k][j]). If any diagonal element > 1 after algorithm, arbitrage exists (cycle with gain).
Python Solution
def floyd_warshall(m, matrix):
for k in range(m):
for i in range(m):
for j in range(m):
matrix[i][j] = max(matrix[i][j], matrix[i][k] * matrix[k][j])
# Check for arbitrage (any diagonal > 1 means profit cycle)
return 'Yes' if any(matrix[i][i] > 1 for i in range(m)) else 'No'
def solution():
case_num = 1
while True:
line = input().strip()
while not line:
line = input().strip()
m = int(line)
if m == 0:
break
currency_index = {input().strip(): i for i in range(m)}
num_exchanges = int(input().strip())
matrix = [[0.0] * m for _ in range(m)]
for _ in range(num_exchanges):
c1, rate, c2 = input().strip().split()
matrix[currency_index[c1]][currency_index[c2]] = float(rate)
print(f'Case {case_num}: {floyd_warshall(m, matrix)}')
case_num += 1
solution()
Complexity Analysis
- Time Complexity: O(N^3) per test case
- Space Complexity: O(N^2)
Social Network
Problem Information
- Source: SPOJ
- Difficulty: Secret
- Time Limit: 1000ms
- Memory Limit: 1536MB
Problem Statement
Given a social network represented as a friendship matrix, find the person who can make the most new friends through existing friends (friends-of-friends). A person can become friends with someone who is a friend of their friend but not already their direct friend.
Input Format
- T: number of test cases
- For each test case:
- M x M matrix where ‘Y’ means friendship exists, ‘N’ means no friendship
Output Format
- For each test case: person_index max_new_friends (0-indexed person who gains most new friends through friend-of-friend connections)
Example
Input:
1
NYNN
YNYN
NYNY
NNYN
Output:
0 2
Person 0 is friends with person 1. Person 1 is friends with person 2. Person 2 is friends with person 3. Person 0 can become friends with persons 2 and 3 (friends-of-friends), gaining 2 new friends - the most of anyone.
Solution
Approach
Use modified Floyd-Warshall concept for transitive closure. For each person i, count people j where i and j are not friends directly but share a common friend k (matrix[i][k]=’Y’ and matrix[k][j]=’Y’). Track which person gains the most potential new friends.
Python Solution
def floyd_warshall(m, matrix):
# Track direct friendships
connected = [[matrix[i][j] == 'Y' for j in range(m)] for i in range(m)]
# Count new friends through friend-of-friend
new_friends = [0] * m
for k in range(m):
for i in range(m):
for j in range(m):
if not connected[i][j] and i != j and matrix[i][k] == 'Y' and matrix[k][j] == 'Y':
connected[i][j] = True
new_friends[i] += 1
# Find person with most new friends
best_person = max(range(m), key=lambda i: new_friends[i])
print(best_person, new_friends[best_person])
def solution():
t = int(input())
for _ in range(t):
first_line = input().strip()
m = len(first_line)
matrix = [first_line] + [input().strip() for _ in range(m - 1)]
floyd_warshall(m, matrix)
solution()
Complexity Analysis
- Time Complexity: O(T * M^3)
- Space Complexity: O(M^2)
Meeting Prof. Miguel
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Two people (young and old) want to meet. Each has their own transportation network (some roads are unidirectional, some bidirectional). Find meeting points where the total travel cost is minimized. Output the minimum cost and all cities where they can meet with that cost.
Input Format
- Multiple test cases until N=0
- For each test case:
- N: number of streets
- N lines: age direction city1 city2 cost
- age: Y (young) or O (old)
- direction: U (unidirectional) or B (bidirectional)
- Start positions: young_start old_start
Output Format
- Minimum total cost and meeting city/cities, or “You will never meet.”
Example
Input:
4
Y U A B 10
Y U B C 20
O U D C 30
O U D A 15
A D
0
Output:
45 A C
Young starts at A, Old starts at D. Meeting at A: Young cost 0, Old cost 15. Total 15. Meeting at C: Young cost 30 (A->B->C), Old cost 30. Total 60. Best meeting point is A with cost 45 (considering both paths).
Solution
Approach
Build separate graphs for young and old person. Run Floyd-Warshall on both graphs. Find city minimizing young_dist[start_y][city] + old_dist[start_o][city]. Output all cities achieving minimum cost.
Python Solution
INF = float('inf')
MAXN = 26
def floyd_warshall(young_graph, old_graph, start_young, start_old):
for k in range(MAXN):
for i in range(MAXN):
for j in range(MAXN):
young_graph[i][j] = min(young_graph[i][j], young_graph[i][k] + young_graph[k][j])
old_graph[i][j] = min(old_graph[i][j], old_graph[i][k] + old_graph[k][j])
# Find minimum meeting cost
min_dist = min(
young_graph[start_young][i] + old_graph[start_old][i]
for i in range(MAXN)
)
if min_dist >= INF:
print('You will never meet.')
else:
# Find all cities with minimum cost
meeting_cities = [
chr(ord('A') + i)
for i in range(MAXN)
if young_graph[start_young][i] + old_graph[start_old][i] == min_dist
]
print(f"{min_dist} {' '.join(meeting_cities)}")
def solution():
while True:
n = int(input().strip())
if n == 0:
break
young_graph = [[INF] * MAXN for _ in range(MAXN)]
old_graph = [[INF] * MAXN for _ in range(MAXN)]
for i in range(MAXN):
young_graph[i][i] = old_graph[i][i] = 0
for _ in range(n):
parts = input().strip().split()
age, direction, city1, city2, cost = parts[0], parts[1], parts[2], parts[3], int(parts[-1])
x, y = ord(city1) - ord('A'), ord(city2) - ord('A')
if x != y:
graph = young_graph if age == 'Y' else old_graph
graph[x][y] = cost
if direction == 'B':
graph[y][x] = cost
start_young, start_old = (ord(c) - ord('A') for c in input().strip().split())
floyd_warshall(young_graph, old_graph, start_young, start_old)
solution()
Complexity Analysis
- Time Complexity: O(26^3) = O(1) per test case (constant alphabet size)
- Space Complexity: O(26^2) = O(1)
Asterix and Obelix
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Asterix and Obelix travel between cities. Each city has a “feast cost” that Obelix must pay when visiting. The total trip cost is the sum of road costs plus the maximum feast cost of any city visited on the path. Find minimum total cost for queries between city pairs.
Input Format
- Multiple test cases until C=0
- For each test case:
- C R Q: cities, roads, queries
- C feast costs for each city
- R lines with c1 c2 d: road between c1 and c2 with distance d
- Q lines with c1 c2: query for minimum cost from c1 to c2
Output Format
- For each case: “Case #X” followed by minimum costs for each query (-1 if impossible)
Example
Input:
4 5 2
10 20 30 40
1 2 5
1 3 10
2 4 7
2 3 3
3 4 2
1 4
2 3
Output:
Case #1
47
33
Query 1->4: Path 1->2->4 has distance 5+7=12, max feast cost is max(10,20,40)=40, total=52. Path 1->3->4 has distance 10+2=12, max feast is max(10,30,40)=40, total=52. Best path gives 47.
Solution
Approach
Use modified Floyd-Warshall tracking both path distance and maximum feast cost. For each intermediate vertex k, update if new path has lower total cost (distance + max_feast_cost). Run multiple iterations to ensure convergence.
Python Solution
INF = float('inf')
def floyd_warshall(m, graph, case_number, queries, feast_cost):
dist = [[graph[i][j] for j in range(m)] for i in range(m)]
max_feast = [[max(feast_cost[i], feast_cost[j]) for j in range(m)] for i in range(m)]
for i in range(m):
max_feast[i][i] = feast_cost[i]
for _ in range(2): # Multiple iterations for convergence
for k in range(m):
for i in range(m):
for j in range(m):
new_feast = max(max_feast[i][k], max_feast[k][j])
new_total = dist[i][k] + dist[k][j] + new_feast
old_total = dist[i][j] + max_feast[i][j]
if new_total < old_total:
dist[i][j] = dist[i][k] + dist[k][j]
max_feast[i][j] = new_feast
print(f'Case #{case_number}')
for src, dest in queries:
cost = dist[src - 1][dest - 1]
if cost == INF:
print(-1)
else:
print(cost + max_feast[src - 1][dest - 1])
def solution():
case_num = 1
while True:
line = input().strip()
while not line:
line = input().strip()
c, r, q = map(int, line.split())
if c == 0:
break
if case_num != 1:
print()
feast_cost = list(map(int, input().strip().split()))
graph = [[INF] * c for _ in range(c)]
for _ in range(r):
c1, c2, d = map(int, input().strip().split())
graph[c1 - 1][c2 - 1] = d
graph[c2 - 1][c1 - 1] = d
queries = [tuple(map(int, input().strip().split())) for _ in range(q)]
floyd_warshall(c, graph, case_num, queries, feast_cost)
case_num += 1
solution()
Complexity Analysis
- Time Complexity: O(C^3) per test case
- Space Complexity: O(C^2)
Thunder Mountain
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
Given towns with 2D coordinates, two towns can communicate directly if their distance is at most 10 units. Find the maximum shortest path between any pair of towns (network diameter). If not all towns are connected, output “Send Kurdy” (network needs a messenger).
Input Format
- T: number of test cases
- For each test case:
- N: number of towns
- N lines with x y: coordinates of each town
Output Format
- “Case #X:” followed by the network diameter (maximum shortest path) or “Send Kurdy” if not all towns are reachable
Example
Input:
2
4
0 0
10 0
10 10
0 10
3
0 0
50 0
100 0
Output:
Case #1:
20.0000
Case #2:
Send Kurdy
Case 1: Towns form a 10x10 square. All adjacent towns are within 10 units. Diameter (longest shortest path) is 20 units (e.g., from (0,0) to (10,10) via two edges). Case 2: Towns are 50 units apart, exceeding the 10-unit communication range.
Solution
Approach
Build graph: connect towns within 10 units distance. Floyd-Warshall for all-pairs shortest paths. Find maximum of all shortest paths (diameter). If any pair is unreachable (INF), output “Send Kurdy”.
Python Solution
import math
INF = float('inf')
def floyd_warshall(m, towns):
# Build graph: connect towns within 10 units
dist = [[INF] * m for _ in range(m)]
for i in range(m):
dist[i][i] = 0
for j in range(i + 1, m):
dx, dy = towns[i][0] - towns[j][0], towns[i][1] - towns[j][1]
sq_dist = dx * dx + dy * dy
if sq_dist <= 100: # Within 10 units (10^2 = 100)
distance = math.sqrt(sq_dist)
dist[i][j] = dist[j][i] = distance
# Floyd-Warshall
for k in range(m):
for i in range(m):
for j in range(m):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
# Find network diameter
max_dist = max(dist[i][j] for i in range(m) for j in range(m))
return 0 if max_dist == INF else max_dist
def solution():
t = int(input().strip())
for case in range(t):
m = int(input().strip())
towns = [tuple(map(int, input().strip().split())) for _ in range(m)]
if case != 0:
print()
print(f'Case #{case + 1}:')
result = floyd_warshall(m, towns)
print(f"{result:.4f}" if result > 0 else 'Send Kurdy')
solution()
Complexity Analysis
- Time Complexity: O(T * N^3)
- Space Complexity: O(N^2)
Risk
Problem Information
- Source: UVA
- Difficulty: Secret
- Time Limit: 3000ms
- Memory Limit: 256MB
Problem Statement
The game of Risk has 20 countries. Given the adjacency information for each country, answer queries about the minimum number of borders (edges) that must be crossed to get from one country to another.
Input Format
- Multiple test sets (19 lines of adjacency data per set)
- Line i: number of neighbors of country i+1, followed by neighbor numbers
- After adjacency data: number of queries
- Query lines: source destination
Output Format
- “Test Set #X” followed by formatted output for each query: “source to destination: distance”
Example
Input:
1 3
2 3 6
3 6 7
0
1
0
0
2 4 5
3 7 8 17
0
1 8
0
0
1 9
0
0
0
0
1 20
0
0
5
1 20
2 9
19 5
18 19
2 20
Output:
Test Set #1
1 to 20: 3
2 to 9: 4
19 to 5: 2
18 to 19: 2
2 to 20: 3
Queries ask for minimum borders to cross between countries in the Risk game board.
Solution
Approach
Build undirected graph with 20 nodes from adjacency lists. Floyd-Warshall for all-pairs shortest paths (all edges have weight 1). Answer queries using precomputed distances.
Python Solution
INF = float('inf')
NUM_COUNTRIES = 20
def floyd_warshall(graph, case_number, queries):
dist = [[graph[i][j] for j in range(NUM_COUNTRIES)] for i in range(NUM_COUNTRIES)]
for k in range(NUM_COUNTRIES):
for i in range(NUM_COUNTRIES):
for j in range(NUM_COUNTRIES):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
print(f'Test Set #{case_number}')
for src, dest in queries:
print(f"{src:2d} to {dest:2d}: {dist[src - 1][dest - 1]}")
def solution():
case_num = 1
while True:
graph = [[INF] * NUM_COUNTRIES for _ in range(NUM_COUNTRIES)]
for i in range(NUM_COUNTRIES - 1):
try:
line = list(map(int, input().strip().split()))
except:
return
if not line:
return
num_neighbors = line[0]
for neighbor in line[1:num_neighbors + 1]:
graph[i][neighbor - 1] = 1
graph[neighbor - 1][i] = 1
num_queries = int(input())
queries = [tuple(map(int, input().strip().split())) for _ in range(num_queries)]
floyd_warshall(graph, case_num, queries)
print()
case_num += 1
solution()
Complexity Analysis
- Time Complexity: O(20^3) = O(1) per test case (constant graph size)
- Space Complexity: O(20^2) = O(1)