一、题目 快递公司每日早晨,给每位快递员推送需要淡到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息,请你依据这些信息,给快递员设计一条最短路径,告诉他最短路径的距离。
不限制快递包裹送到客户手中的顺序,但必须保证都送到客户手中;
用例保证一定存在投递站到每位客户之间的路线,但不保证客户与客户之间有路线,客户位置及投递站均允许多次经过;
所有快递送完后,快递员需回到投递站
二、输入 1 2 3 4 5 6 7 8 9 10 11 12 首行输入两个正整数n、m. 接下来n行,输入快递公司发布的 客户快递信息,格式为: 客户id 投递站到客户之间的距离distance 再接下来的m行,是快递员自行查找的 客户与客户之间的距离信息, 格式为:客户1id 客户2id distance 在每行数据中,数据与数据之间均 以单个空格分割规格:
0 <=n <= 10 0 <= m <= 10 0 < 客户id <= 1000 0 < distance <= 10000
三、输出
四、示例 示例一
1 2 3 4 5 6 7 8 输入: 2 1 1 1000 2 1200 1 2 300 输出: 2500
说明: 快递员先把快递送到客户1手中,接下来直接走客户1到客户2之间的直通线路,最后走投递站和客户2之间的路,回到投递站,距离为1000+300+1200= 2500
示例二
1 2 3 4 5 6 7 8 9 10 11 输入: 5 1 5 1000 9 1200 17 300 132 700 500 2300 5 9 400 输出: 9200
五、题解
Floyd-Warshall算法求无向图任意 2 点最小距离 + 动态规划求解走过所有节点的最小距离
输入参数中客户节点数不是 1,2,3 递增的。需要映射转换为数组索引
难点是动态规划状态表示 dp[i][j],走过 i 状态表示的节点,当前在 j 节点时走过的最小距离。需要注意的是对于 dp[2][1]表示走过第 1 个客户节点(二进制表示为 10),当前在第 1 号节点,值为 dist[0][1],此时状态值并不包括 0 号节点
动态规划中求返回 0 号节点最值是状态(1 << (n + 1)) - 2
各种 ChatGPT都做出来的是错误的题解,可能跟网上没有完整的答案有关系
5.1 Java 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 package org.stone.study.algo.ex202411;import java.util.*;import java.io.*;public class FloydWarshall { public static final int INF = Integer.MAX_VALUE / 2 ; public static void main (String[] args) throws IOException { Scanner scanner = new Scanner (System.in); String[] line = scanner.nextLine().split(" " ); int n = Integer.parseInt(line[0 ]); int m = Integer.parseInt(line[1 ]); Map<Integer, Integer> custToIndex = new HashMap <>(); int [][] dist = new int [n + 1 ][n + 1 ]; for (int i = 0 ; i <= n; i++) { Arrays.fill(dist[i], INF); dist[i][i] = 0 ; } int index = 1 ; for (int i = 0 ; i < n; i++) { line = scanner.nextLine().split(" " ); int id = Integer.parseInt(line[0 ]); int distance = Integer.parseInt(line[1 ]); dist[0 ][index] = distance; dist[index][0 ] = distance; custToIndex.put(id, index); ++index; } for (int i = 0 ; i < m; i++) { line = scanner.nextLine().split(" " ); int id1 = custToIndex.get(Integer.parseInt(line[0 ])); int id2 = custToIndex.get(Integer.parseInt(line[1 ])); int distance = Integer.parseInt(line[2 ]); dist[id1][id2] = distance; dist[id2][id1] = distance; } int minDistance = getMinDistance(dist, n); System.out.println(minDistance); } private static int getMinDistance (int [][] dist, int n) { for (int k = 0 ; k <= n; k++) { for (int i = 0 ; i <= n; i++) { for (int j = 0 ; j <= n; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; } } } } int [][] dp = new int [1 << (n + 1 )][n + 1 ]; for (int [] row : dp) { Arrays.fill(row, INF); } for (int i = 1 ; i <= n; i++) { dp[1 << i][i] = dist[0 ][i]; } for (int mask = 1 ; mask < (1 << (n + 1 )); mask++) { for (int i = 1 ; i <= n; i++) { if ((mask & (1 << i)) != 0 ) { for (int j = 0 ; j <= n; j++) { if (i != j && (mask & (1 << j)) != 0 ) { dp[mask][i] = Math.min(dp[mask][i], dp[mask ^ (1 << i)][j] + dist[j][i]); } } } } } int minDistance = INF; for (int i = 1 ; i <= n; i++) { minDistance = Math.min(minDistance, dp[(1 << (n + 1 )) - 2 ][i] + dist[i][0 ]); } return minDistance == INF ? -1 : minDistance; } }
5.2 Python实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 INF = float ('inf' ) def get_min_distance (dist, n ): for k in range (n + 1 ): for i in range (n + 1 ): for j in range (n + 1 ): if dist[i][k] + dist[k][j] < dist[i][j]: dist[i][j] = dist[i][k] + dist[k][j] dp = [[INF] * (n + 1 ) for _ in range (1 << (n + 1 ))] for i in range (1 , n + 1 ): dp[1 << i][i] = dist[0 ][i] for mask in range (1 , 1 << (n + 1 )): for i in range (1 , n + 1 ): if mask & (1 << i): for j in range (n + 1 ): if i != j and mask & (1 << j): dp[mask][i] = min (dp[mask][i], dp[mask ^ (1 << i)][j] + dist[j][i]) min_distance = INF for i in range (1 , n + 1 ): min_distance = min (min_distance, dp[(1 << (n + 1 )) - 2 ][i] + dist[i][0 ]) return -1 if min_distance == INF else int (min_distance) def main (): n, m = map (int , input ().split()) cust_to_index = {} dist = [[INF] * (n + 1 ) for _ in range (n + 1 )] for i in range (n + 1 ): dist[i][i] = 0 for i in range (n): cust_id, distance = map (int , input ().split()) cust_to_index[cust_id] = i + 1 dist[0 ][i + 1 ] = distance dist[i + 1 ][0 ] = distance for i in range (m): cid1, cid2, distance = map (int , input ().split()) id1 = cust_to_index[cid1] id2 = cust_to_index[cid2] dist[id1][id2] = distance dist[id2][id1] = distance min_distance = get_min_distance(dist, n) print (min_distance) if __name__ == "__main__" : main()