旅行商問題
阿新 • • 發佈:2021-10-28
給 n 個城市(從 1 到 n),城市和無向道路成本之間的關係為3元組 [A, B, C](在城市 A 和城市 B 之間有一條路,成本是 C)我們需要從1開始找到的旅行所有城市的付出最小的成本。
心之所向,素履以往 生如逆旅,一葦以航import java.util.Arrays; import java.util.List; public class Solution { /** * O(n!) * 從 start開始,遍歷完所需最小代價 * * @param roads * @param start * @return */ private static int solve1(int[][] roads, List<Integer> posts, int start) { int num = 0; /** * 集合中沒有郵局,則結束 */ for (int i = 0; i < posts.size(); ++i) { if (posts.get(i) != null) { num++; } } if (num == 1) { return 0; } /** * 設定當前郵局為已訪問 */ posts.set(start - 1, null); int min = Integer.MAX_VALUE; for (int i = 0; i < posts.size(); ++i) { if (posts.get(i) != null && roads[start - 1][i] != Integer.MAX_VALUE) { int next = solve1(roads, posts, i + 1); if (next != Integer.MAX_VALUE) { min = Math.min(min, next + roads[start - 1][i]); } } } posts.set(start - 1, 1); return min; } private static int lowBit(int n) { return n & (-n); } private static int reset(int cityStatus, int index) { return cityStatus & (~(1 << (index - 1))); } private static int set(int cityStatus, int index) { return cityStatus | (1 << (index - 1)); } private static boolean exist(int cityStatus, int index) { return (cityStatus & (1 << (index - 1))) != 0; } /** * O(n!) * * @param roads * @param cityStatus * @param start * @return */ private static int solve2(int[][] roads, int cityStatus, int start) { /** * 只剩一個郵局 */ if (lowBit(cityStatus) == cityStatus) { return 0; } /** * 設定當前郵局為已訪問 */ cityStatus = reset(cityStatus, start); int min = Integer.MAX_VALUE; for (int i = 0; i < roads.length; ++i) { if ((cityStatus & (1 << i)) != 0 && roads[start - 1][i] != Integer.MAX_VALUE) { int next = solve2(roads, cityStatus, i + 1); if (next != Integer.MAX_VALUE) { min = Math.min(min, next + roads[start - 1][i]); } } } return min; } private static int solve3(int[][] roads, int cityStatus, int start, int[][] dp) { if (dp[cityStatus][start - 1] != -1) { return dp[cityStatus][start - 1]; } /** * 只剩一個郵局 */ if (lowBit(cityStatus) == cityStatus) { dp[cityStatus][start - 1] = 0; return 0; } /** * 設定當前郵局為已訪問 */ cityStatus = reset(cityStatus, start); int min = Integer.MAX_VALUE; for (int i = 0; i < roads.length; ++i) { if ((cityStatus & (1 << i)) != 0 && roads[start - 1][i] != Integer.MAX_VALUE) { int next = solve3(roads, cityStatus, i + 1, dp); if (next != Integer.MAX_VALUE) { min = Math.min(min, next + roads[start - 1][i]); } } } cityStatus = set(cityStatus, start); dp[cityStatus][start - 1] = min; return min; } /** * O(2^n * n ^ 2) */ private static int solve4(int[][] roads) { int n = roads.length; int[][] dp = new int[1 << n][n]; for (int status = 1; status <= (1 << n) - 1; ++status) { /** * 一個郵局,預設就是0 */ if (lowBit(status) == status) { continue; } for (int start = 0; start < n; ++start) { if (exist(status, start + 1)) { int min = Integer.MAX_VALUE; int newStatus = reset(status, start + 1); for (int k = 0; k < n; k++) { if ((newStatus & (1 << k)) != 0 && roads[start][k] != Integer.MAX_VALUE) { int next = dp[newStatus][k]; if (next != Integer.MAX_VALUE) { min = Math.min(min, next + roads[start][k]); } } } dp[status][start] = min; } } } return dp[(1 << n) - 1][0]; } public static int minCost(int n, int[][] roads) { if (n <= 1 || roads.length == 0 || roads[0].length == 0) { return 0; } int[][] newRoads = new int[n][n]; for (int i = 0; i < n; ++i) { Arrays.fill(newRoads[i], Integer.MAX_VALUE); } for (int i = 0; i < roads.length; ++i) { newRoads[roads[i][0] - 1][roads[i][1] - 1] = Math.min(newRoads[roads[i][0] - 1][roads[i][1] - 1], roads[i][2]); newRoads[roads[i][1] - 1][roads[i][0] - 1] = Math.min(newRoads[roads[i][1] - 1][roads[i][0] - 1], roads[i][2]); } return solve4(newRoads); } }