一. 题目-快递员的烦恼
快递公司每日早晨,给每位快递员推送需要送到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息,请你依据这些信息,给快递员设计一条最短路径,告诉他最短路径的距离。
注意:
- 不限制快递包裹送到客户手中的顺序,但必须保证都送到客户手中
- 用例保证一定存在投递站到每位客户之间的路线,但不保证客户与客户之间有路线,客户位置及投递站均允许多次经过
- 所有快递送完后,快递员需回到投递站
输入描述:首行输入两个正整数n、m
接下来n行,输入快递公司发布的客户快递信息,格式为:客户id 投递站到客户之间的距离distance
再接下来的m行,是快递员自行查找的客户与客户之间的距离信息,格式为:客户1id 客户2id distance
在每行数据中,数据与数据之间均以单个空格分割
规格:
0 < n <= 10
0 <= m <= 10
0 < 客户id <= 1000
0 < distance <= 10000
输出描述:最短路径距离,如无法找到,请输出-1
示例
示例1
输入:2 1
1 1000
2 1200
1 2 300
输出:2500
说明:路径1:快递员先把快递送到客户1手中,接下来直接走客户1到客户2之间的直通线路,最后走投递站和客户2之间的路,回到投递站,距离为1000 + 300 + 1200 =2500
路径2:快递员先把快递送到客户1手中,接下来回到快递站,再出发把客户2的快递送过去,再回到投递站,距离为1000 + 1000 + 1200 + 1200 = 4400
路径3:快递员先把快递送到客户2手中,接下来直接走客户2到客户1之间的直通线路,最后走投递站和客户1之间的路,回到投递站,距离为1200 + 300 + 1000 =2500
其他路径……
所有路径中,最短路径距离为2500
示例2
输入:5 1
5 1000
9 1200
17 300
132 700
500 2300
5 9 400
输出:9200
说明:在所有可行的路径中,最短路径长度为1000 + 400 + 1200 + 300 + 300 + 700 + 700 + 2300 + 2300 = 9200
二.解题思路
当解决这个问题时,我们可以按照以下步骤进行:
-
构建图(Graph): 将问题抽象为一个图,其中节点表示客户和投递站,边表示客户之间或客户与投递站之间的距离。这里采用邻接表的方式表示图,其中每个节点有一个列表,记录与其相连的节点和对应的距离。
-
计算最短路径: 使用最短路径算法,比如Dijkstra算法,计算从投递站到每个客户的最短路径。这一步旨在找到每个客户到投递站的最短距离。
-
遍历可能的路径: 对于每个客户,我们考虑以该客户为起点,通过其他客户形成路径。在此过程中,我们要确保所有客户都被访问到。可以使用深度优先搜索(DFS)或回溯法来尝试不同的路径组合。
-
计算路径长度: 对于每一种可能的路径,计算其总长度,包括从投递站到第一个客户,以及客户之间的距离。在每个客户之间可以使用已经计算好的最短路径。
-
找到最短路径: 在所有可能的路径中,找到总长度最短的一条路径。
-
输出结果: 输出最短路径的总长度。
通过这个思路,我们可以有效地解决问题,并找到最短路径的距离。
三.题解代码
Python题解代码
from sre_parse import State
n, m = [int(i) for i in input().split()]
dis = [[None] * (n + 1) for i in range(n + 1)]
mapping = {}
for i in range(n):
uid, d = [int(j) for j in input().split()]
mapping[uid] = i + 1
dis[0][i + 1] = dis[i + 1][0] = d
for i in range(m):
x, y, d = [int(j) for j in input().split()]
x = mapping[x]
y = mapping[y]
dis[x][y] = dis[y][x] = d
f = [[None] * (n + 1) for i in range(1 << n)]
q = [[0, 0, 0]]
f[0][0] = 0
head, tail = 0, 1
while head < tail:
now_state, now, now_d = q[head]
head += 1
for nxt in range(n + 1):
if nxt != now and dis[now][nxt] is not None:
if nxt == 0:
nxt_state = now_state
else:
nxt_state = now_state | (1 << (nxt - 1))
if f[nxt_state][nxt] is None or f[nxt_state][nxt] > f[now_state][now] + dis[now][nxt]:
f[nxt_state][nxt] = f[now_state][now] + dis[now][nxt]
q.append([nxt_state, nxt, f[nxt_state][nxt]])
tail += 1
print(f[-1][0])
JAVA题解代码
import java.util.Scanner;
import java.util.*;
import java.util.stream.Stream;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] nums = split(in.nextLine(), " ");
int n = nums[0];
int r = nums[1];
int[][] matrix = new int[n + 1][n + 1];
for (int i = 0; i < n+1; i++) {
for (int j = 0; j < n+1; j++) {
matrix[i][j] = Integer.MAX_VALUE;
}
}
int[] distiance_map = new int[2000];
for (int i = 0; i < n; i++) {
int[] nums1 = split(in.nextLine(), " ");
distiance_map[nums1[0]] = i + 1;
matrix[0][i + 1] = nums1[1];
matrix[i + 1][0] = nums1[1];
}
for (int i = 0; i < r; i++) {
int[] nums1 = split(in.nextLine(), " ");
matrix[distiance_map[nums1[0]]][distiance_map[nums1[1]]] = nums1[2];
matrix[distiance_map[nums1[1]]][distiance_map[nums1[0]]] = nums1[2];
}
int[][] cache = new int[1024][n + 1];
for (int i = 0; i < 1024; i++) {
for (int j = 0; j < n+1; j++) {
cache[i][j] = Integer.MAX_VALUE;
}
}
LinkedList<int[]> queue = new LinkedList<>();
queue.add(new int[]{0, 0});
cache[0][0] = 0;
while (true){
if(queue.isEmpty()){
break;
} else {
int[] position = queue.poll();
int i=0;
while(true){
if(i>n){
break;
} else {
if(i==position[1] || matrix[position[1]][i] == Integer.MAX_VALUE){
i+=1;
continue;
}
int new_situation = position[0];
if(i > 0){
new_situation = position[0] | Double.valueOf(Math.pow(2, i-1)).intValue();
}
if (cache[new_situation][i] > cache[position[0]][position[1]] + matrix[position[1]][i]) {
cache[new_situation][i] = cache[position[0]][position[1]] + matrix[position[1]][i];
queue.add(new int[]{new_situation, i});
}
}
i+=1;
}
}
}
int final_distiance = cache[Double.valueOf(Math.pow(2, n)).intValue() - 1][0];
if(final_distiance == Integer.MAX_VALUE){
System.out.println(-1);
} else {
System.out.println(final_distiance);
}
}
public static int[] split(String input_str,String chars){
String[] tmp2 = input_str.split(chars);
int[] results = new int[tmp2.length];
for (int i = 0; i < tmp2.length; i++) {
results[i] = Integer.parseInt(tmp2[i]);
}
return results;
}
}
C/C++题解代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 1e9;
int n, m;
vector<int> customer_distance;
vector<vector<int>> distance;
void floyd_warshall() {
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
distance[i][j] = min(distance[i][j], distance[i][k] + distance[k][j]);
}
}
}
}
int find_min_distance() {
int min_distance = INF;
for (int i = 0; i < n; i++) {
int total_distance = 0;
for (int j = 0; j < n; j++) {
if (i != j) {
total_distance += distance[i][j];
}
}
min_distance = min(min_distance, total_distance);
}
return min_distance;
}
int main() {
cin >> n >> m;
customer_distance.resize(n);
distance.resize(n, vector<int>(n, INF));
for (int i = 0; i < n; i++) {
cin >> customer_distance[i];
distance[i][i] = 0;
}
for (int i = 0; i < m; i++) {
int id1, id2, d;
cin >> id1 >> id2 >> d;
distance[id1 - 1][id2 - 1] = d;
distance[id2 - 1][id1 - 1] = d;
}
floyd_warshall();
cout << find_min_distance() << endl;
return 0;
}
JS题解代码
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function solve() {
let idx = 0;
const inf = 1e9;
const g = [];
const mapp = new Map();
const get = (x) => {
if (mapp.has(x)) {
return mapp.get(x);
}
return mapp.set(x, ++idx).get(x);
};
rl.question('', (line) => {
const [n, m] = line.split(' ').map(Number);
for (let i = 0; i <= n; ++i) {
g.push(new Array(n + 1).fill(inf));
}
rl.question('', (line) => {
const values = line.split(' ').map(Number);
for (let i = 1; i <= n; ++i) {
const x = get(values[i - 1]);
rl.question('', (line) => {
g[0][x] = g[x][0] = parseInt(line);
});
}
for (let i = 0; i < m; ++i) {
rl.question('', (line) => {
const [u, v, w] = line.split(' ').map(Number);
const uu = get(u);
const vv = get(v);
g[uu][vv] = g[vv][uu] = w;
});
}
// Floyd
for (let i = 0; i <= n; ++i) {
for (let j = 0; j <= n; ++j) {
for (let k = 0; k <= n; ++k) {
g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
}
}
}
// DP with bitmasking, initialize to infinity representing unreachable
const f = new Array(1 << (n + 1)).fill(null).map(() => new Array(n + 1).fill(inf));
f[1][0] = 0;
for (let i = 1; i < (1 << (n + 1)); ++i) {
for (let j = 0; j <= n; ++j) {
if ((i >> j) & 1) {
for (let k = 0; k <= n; ++k) {
f[i | (1 << k)][k] = Math.min(f[i][j] + g[j][k], f[i | (1 << k)][k]);
}
}
}
}
console.log(f[(1 << (n + 1)) - 1][0]);
rl.close();
});
});
}
solve();
四.代码讲解(Java&Python&C++&JS分别讲解)
Python题解代码解析:
-
输入处理: 从标准输入读取两个整数 n 和 m,分别表示客户数和自查找的客户之间距离信息的数量。
-
数组初始化: 初始化二维数组 dis 用于存储客户之间的距离,以及字典 mapping 用于映射客户id到数组索引。
-
读取客户信息: 通过循环读取 n 行输入,每行包含客户id和投递站到客户的距离。将客户id映射到数组索引,同时记录投递站到客户的距离。
-
读取自查找信息: 通过循环读取 m 行输入,每行包含两个客户id和客户之间的距离。将客户id映射到数组索引,同时记录客户之间的距离。
-
动态规划: 使用动态规划,初始化二维数组 f 和队列 q,其中 f 用于记录状态转移的最小距离,q 用于广度优先搜索。
-
状态转移: 通过状态转移更新 f 数组,表示经过某些客户的状态下,到达某个客户的最小距离。使用队列实现广度优先搜索。
-
输出结果: 输出 f 数组的最后一行最后一列元素,即到达所有客户并回到投递站的最小距离。
JAVA题解代码解析:
-
输入处理: 使用 Scanner 读取一行输入,分割得到 n 和 r。
-
矩阵初始化: 初始化二维矩阵 matrix,用于存储客户之间的距离。初始化距离映射数组 distance_map,用于将客户id映射到数组索引。
-
读取客户信息: 通过循环读取 n 行输入,每行包含客户id和投递站到客户的距离。将客户id映射到数组索引,同时记录投递站到客户的距离。
-
读取自查找信息: 通过循环读取 r 行输入,每行包含两个客户id和客户之间的距离。将客户id映射到数组索引,同时记录客户之间的距离。
-
动态规划: 使用动态规划,初始化二维数组 cache 和队列 queue,其中 cache 用于记录状态转移的最小距离,queue 用于广度优先搜索。
-
状态转移: 通过状态转移更新 cache 数组,表示经过某些客户的状态下,到达某个客户的最小距离。使用队列实现广度优先搜索。
-
输出结果: 输出 cache 数组的最后一行第一列元素,即到达所有客户并回到投递站的最小距离。
C/C++题解代码解析:
-
包含头文件: 包含必要的头文件,使用 C++ 的标准库。
-
常量和变量定义: 定义常量 INF 用于表示无穷大,以及 n、m、customer_distance 和 distance 用于存储客户和客户之间的距离。
-
Floyd-Warshall算法: 使用 Floyd-Warshall 算法计算所有客户之间的最短路径。
-
计算最小距离: 遍历所有客户,计算经过不同客户的路径中最小的总距离。
-
输出结果: 输出最小距离。
JS题解代码解析:
-
使用readline模块: 使用 Node.js 的 readline 模块处理输入。
-
函数solve: 定义了一个 solve 函数,其中实现了输入处理、矩阵初始化、Floyd算法、DP算法等步骤。
-
输入处理: 通过递归调用 rl.question() 实现输入处理,获取 n、m 以及客户和客户之间的距离信息。
-
矩阵初始化: 初始化二维数组 g 用于存储客户之间的距离,以及 Map 对象 mapp 用于映射客户id到数组索引。
-
Floyd算法: 使用 Floyd 算法计算所有客户之间的最短路径。
-
DP算法: 使用DP算法和位掩码实现状态压缩,初始化数组 f,通过队列实现广度优先搜索。
-
输出结果: 输出最终结果,即到达所有客户并回到投递站的最小距离。
总体来说,这些代码都采用了动态规划的思想,通过计算最短路径和状态转移来求解问题。