From 4c45400e79ba8210805cc677d3515c54df3cd951 Mon Sep 17 00:00:00 2001 From: I761212 Date: Wed, 22 Oct 2025 21:55:13 +0530 Subject: [PATCH 1/4] TSP algo --- .../travelling_sales_person.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 dynamic_programming/travelling_sales_person.py diff --git a/dynamic_programming/travelling_sales_person.py b/dynamic_programming/travelling_sales_person.py new file mode 100644 index 000000000000..0e4e0655b82d --- /dev/null +++ b/dynamic_programming/travelling_sales_person.py @@ -0,0 +1,65 @@ +""" +Dynamic Programming: Travelling Salesman Problem (TSP) +----------------------------------------------------- +Solves the classic TSP using the Held–Karp dynamic programming approach. + +Time Complexity: O(n^2 * 2^n) +Space Complexity: O(n * 2^n) + +Example: + >>> cost = [ + ... [0, 10, 15, 20], + ... [10, 0, 35, 25], + ... [15, 35, 0, 30], + ... [20, 25, 30, 0] + ... ] + >>> travelling_salesman(cost) + 80 +""" + +from functools import lru_cache + + +def travelling_salesman(cost_matrix: list[list[int]]) -> int: + """ + Returns the minimum travel cost for visiting all cities and returning + to the starting city (0-indexed), using the Held–Karp DP approach. + + Args: + cost_matrix (list[list[int]]): A square matrix where cost_matrix[i][j] + represents the cost of traveling from city i to city j. + + Returns: + int: The minimum total cost of the tour. + """ + n = len(cost_matrix) + all_visited = (1 << n) - 1 # bitmask with all cities visited + + @lru_cache(maxsize=None) + def dp(mask: int, pos: int) -> int: + # Base case: all cities visited, return cost to go back to start + if mask == all_visited: + return cost_matrix[pos][0] + + ans = float("inf") + for city in range(n): + # If city not yet visited + if not (mask & (1 << city)): + new_cost = cost_matrix[pos][city] + dp(mask | (1 << city), city) + ans = min(ans, new_cost) + return ans + + # Start from city 0 with only it visited + return dp(1, 0) + + +if __name__ == "__main__": + # Example test case + cost = [ + [0, 10, 15, 20], + [10, 0, 35, 25], + [15, 35, 0, 30], + [20, 25, 30, 0], + ] + + print("Minimum tour cost:", travelling_salesman(cost)) From 4eb73b620ced4f1e69e3915c81f02ebd0105e40a Mon Sep 17 00:00:00 2001 From: Aishaan Datt <63548745+aishaandatt@users.noreply.github.com> Date: Wed, 22 Oct 2025 22:36:44 +0530 Subject: [PATCH 2/4] Fix formatting and update cache decorator --- dynamic_programming/travelling_sales_person.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dynamic_programming/travelling_sales_person.py b/dynamic_programming/travelling_sales_person.py index 0e4e0655b82d..be352ef8e219 100644 --- a/dynamic_programming/travelling_sales_person.py +++ b/dynamic_programming/travelling_sales_person.py @@ -1,7 +1,7 @@ """ Dynamic Programming: Travelling Salesman Problem (TSP) ----------------------------------------------------- -Solves the classic TSP using the Held–Karp dynamic programming approach. +Solves the classic TSP using the Held Karp dynamic programming approach. Time Complexity: O(n^2 * 2^n) Space Complexity: O(n * 2^n) @@ -17,13 +17,13 @@ 80 """ -from functools import lru_cache +import functools def travelling_salesman(cost_matrix: list[list[int]]) -> int: """ Returns the minimum travel cost for visiting all cities and returning - to the starting city (0-indexed), using the Held–Karp DP approach. + to the starting city (0-indexed), using the Held Karp DP approach. Args: cost_matrix (list[list[int]]): A square matrix where cost_matrix[i][j] @@ -35,7 +35,7 @@ def travelling_salesman(cost_matrix: list[list[int]]) -> int: n = len(cost_matrix) all_visited = (1 << n) - 1 # bitmask with all cities visited - @lru_cache(maxsize=None) + @functools.cache def dp(mask: int, pos: int) -> int: # Base case: all cities visited, return cost to go back to start if mask == all_visited: From d7134b06cd116bc4af81041bb552057bfb4271d1 Mon Sep 17 00:00:00 2001 From: Aishaan Datt <63548745+aishaandatt@users.noreply.github.com> Date: Thu, 23 Oct 2025 21:00:01 +0530 Subject: [PATCH 3/4] Change return type of travelling_salesman to float --- dynamic_programming/travelling_sales_person.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/travelling_sales_person.py b/dynamic_programming/travelling_sales_person.py index be352ef8e219..81076b929f4f 100644 --- a/dynamic_programming/travelling_sales_person.py +++ b/dynamic_programming/travelling_sales_person.py @@ -20,7 +20,7 @@ import functools -def travelling_salesman(cost_matrix: list[list[int]]) -> int: +def travelling_salesman(cost_matrix: list[list[int]]) -> float: """ Returns the minimum travel cost for visiting all cities and returning to the starting city (0-indexed), using the Held Karp DP approach. From 1a0dd318519234e48b851a806cb3e83750971fb6 Mon Sep 17 00:00:00 2001 From: Aishaan Datt <63548745+aishaandatt@users.noreply.github.com> Date: Thu, 23 Oct 2025 21:40:31 +0530 Subject: [PATCH 4/4] Change return type of dp function to float --- dynamic_programming/travelling_sales_person.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic_programming/travelling_sales_person.py b/dynamic_programming/travelling_sales_person.py index 81076b929f4f..e309ed7e5428 100644 --- a/dynamic_programming/travelling_sales_person.py +++ b/dynamic_programming/travelling_sales_person.py @@ -30,13 +30,13 @@ def travelling_salesman(cost_matrix: list[list[int]]) -> float: represents the cost of traveling from city i to city j. Returns: - int: The minimum total cost of the tour. + float: The minimum total cost of the tour. """ n = len(cost_matrix) all_visited = (1 << n) - 1 # bitmask with all cities visited @functools.cache - def dp(mask: int, pos: int) -> int: + def dp(mask: int, pos: int) -> float: # Base case: all cities visited, return cost to go back to start if mask == all_visited: return cost_matrix[pos][0]