题目描述
快递公司每日早晨,给每位快递员推送需要送到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息,请你依据这些信息,给快递员设计一条最短路径,告诉他最短路径的距离。
注意:
- 不限制快递包裹送到客户手中的顺序,但必须保证都送到客户手中
- 用例保证一定存在投递站到每位客户之间的路线,但不保证客户与客户之间有路线,客户位置及投递站均允许多次经过
- 所有快递送完后,快递员需回到投递站
输入描述
首行输入两个正整数n、m
接下来 n 行,输入快递公司发布的客户快递信息,格式为:
客户id 投递站到客户之间的距离distance
再接下俩的 m 行,是快递员自行查找的客户与客户之间的距离信息,格式为
客户id1 客户id2 distance
在每行数据中,数据与数据之间均以单个空格分隔
规格:
- 0 < n ≤ 10
- 0 ≤ m ≤ 10
- 0 < 客户id ≤ 1000
- 0 < distance ≤ 10000
输出描述
最短路径距离,如无法找到,请输出-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 |
输入 | 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 |
题目解析
下图中 0节点 代表快递站。
用例1图示
用例2图示
本题的原型题应该是:
具体解析可以参考上面链接博客。
JS算法源码
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
const [n, m] = (await readline()).split(" ").map(Number);
// floyd算法需要基于dist和path矩阵求解
// dist[i][j] 用于记录点 i->j 的最短距离,初始时等价于邻接矩阵, 对与不直连的两点,距离为无穷大
const dist = new Array(n + 1)
.fill(0)
.map(() => new Array(n + 1).fill(Infinity));
// path[i][j] 用于记录点 i->j 最短距离情况下需要经过的中转点,初始时默认任意两点间无中转点,即默认path[i][j] = -1
const path = new Array(n + 1).fill(0).map(() => new Array(n + 1).fill(-1));
// 由于本题的客户id不是顺序的,因此这里需要将客户id离散化处理
const map = {};
for (let i = 1; i <= n; i++) {
const [id, dis] = (await readline()).split(" ").map(Number);
// 离散化处理
map[id] = i;
// 投递站到客户之间的距离distance
dist[0][i] = dis;
dist[i][0] = dis;
}
for (let i = 1; i <= m; i++) {
const [id1, id2, dis] = (await readline()).split(" ").map(Number);
const i1 = map[id1];
const i2 = map[id2];
// 客户与客户之间的距离信息
dist[i1][i2] = dis;
dist[i2][i1] = dis;
}
// floyd算法调用
floyd();
// ans记录经过所有点后回到出发点的最短距离
let ans = Infinity;
// 全排列模拟经过所有点的路径
dfs(0, 0, new Array(n + 1).fill(false), 0);
console.log(ans);
// floyd算法求解图中任意两点之间的最短路径
function floyd() {
for (let k = 0; k < n + 1; k++) {
for (let i = 0; i < n + 1; i++) {
for (let j = 0; j < n + 1; j++) {
// newDist是经过k后,i->j的距离
const newDist = dist[i][k] + dist[k][j];
// 如果newDist是i->j的更短路径
if (newDist < dist[i][j]) {
// 则更新i->j的最短距离
dist[i][j] = newDist;
// 且此更短距离需要经过k, path[i][j]即记录 i->j 最短距离下需要经过点 k
path[i][j] = k;
}
}
}
}
}
/**
* 找一条经过所有点的最短路径,我们可以求解所有点形成的全排列,每一个全排列都对应一条经过所有点的路径,只是经过点的先后顺序不同 //
* 求某个全排列过程中,可以通过dist数组,累计上一个点i到下一个点j的最短路径dist[i][j]
*
* @param pre 上一个点, 初始为0,表示从快递站出发
* @param sum 当前全排列路径累计的路径权重
* @param used 全排列used数组,用于标记哪些点已使用过
* @param level 用于记录排列的长度
*/
function dfs(pre, sum, used, level) {
if (level == n) {
// 此时pre是最后一个客户所在点,送完最后一个客户后,快递员需要回到快递站,因此最终累计路径权重为 sum + dist[pre][0]
// 我们保留最小权重路径
ans = Math.min(ans, sum + dist[pre][0]);
return;
}
for (let i = 1; i <= n; i++) {
if (used[i]) continue;
used[i] = true;
dfs(i, sum + dist[pre][i], used, level + 1);
used[i] = false;
}
}
})();
Java算法源码
import java.util.HashMap;
import java.util.Scanner;
public class Main {
static int n;
static int[][] dist;
static int[][] path;
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
int m = sc.nextInt();
// floyd算法需要基于dist和path矩阵求解
// dist[i][j] 用于记录点 i->j 的最短距离,初始时等价于邻接矩阵
dist = new int[n + 1][n + 1];
// path[i][j] 用于记录点 i->j 最短距离情况下需要经过的中转点,初始时默认任意两点间无中转点,即默认path[i][j] = -1
path = new int[n + 1][n + 1];
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
// 初始时默认i,j不相连,即i,j之间距离无穷大
if (i != j) {
dist[i][j] = Integer.MAX_VALUE;
}
path[i][j] = -1;
}
}
// 由于本题的客户id不是顺序的,因此这里需要将客户id离散化处理
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 1; i <= n; i++) {
int id = sc.nextInt();
int dis = sc.nextInt();
// 离散化处理
map.put(id, i);
// 投递站到客户之间的距离distance
dist[0][i] = dis;
dist[i][0] = dis;
}
for (int i = 1; i <= m; i++) {
int id1 = sc.nextInt();
int id2 = sc.nextInt();
int dis = sc.nextInt();
int i1 = map.get(id1);
int i2 = map.get(id2);
// 客户与客户之间的距离信息
dist[i1][i2] = dis;
dist[i2][i1] = dis;
}
// floyd算法调用
floyd();
// ans记录经过所有点后回到出发点的最短距离
ans = Integer.MAX_VALUE;
// 全排列模拟经过所有点的路径
dfs(0, 0, new boolean[n + 1], 0);
System.out.println(ans);
}
// floyd算法求解图中任意两点之间的最短路径
public static void floyd() {
for (int k = 0; k < n + 1; k++) {
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
// newDist是经过k后,i->j的距离
int newDist = dist[i][k] + dist[k][j];
// 如果newDist是i->j的更短路径
if (newDist < dist[i][j]) {
// 则更新i->j的最短距离
dist[i][j] = newDist;
// 且此更短距离需要经过k, path[i][j]即记录 i->j 最短距离下需要经过点 k
path[i][j] = k;
}
}
}
}
}
/**
* 找一条经过所有点的最短路径,我们可以求解所有点形成的全排列,每一个全排列都对应一条经过所有点的路径,只是经过点的先后顺序不同 //
* 求某个全排列过程中,可以通过dist数组,累计上一个点i到下一个点j的最短路径dist[i][j]
*
* @param pre 上一个点, 初始为0,表示从快递站出发
* @param sum 当前全排列路径累计的路径权重
* @param used 全排列used数组,用于标记哪些点已使用过
* @param level 用于记录排列的长度
*/
public static void dfs(int pre, int sum, boolean[] used, int level) {
if (level == n) {
// 此时pre是最后一个客户所在点,送完最后一个客户后,快递员需要回到快递站,因此最终累计路径权重为 sum + dist[pre][0]
// 我们保留最小权重路径
ans = Math.min(ans, sum + dist[pre][0]);
return;
}
for (int i = 1; i <= n; i++) {
if (used[i]) continue;
used[i] = true;
dfs(i, sum + dist[pre][i], used, level + 1);
used[i] = false;
}
}
}
Python算法源码
import sys
# 输入获取
n, m = map(int, input().split())
# floyd算法需要基于dist和path矩阵求解
# dist[i][j] 用于记录点 i->j 的最短距离,初始时等价于邻接矩阵
dist = [[sys.maxsize] * (n + 1) for _ in range(n + 1)]
# path[i][j] 用于记录点 i->j 最短距离情况下需要经过的中转点,初始时默认任意两点间无中转点,即默认path[i][j] = -1
path = [[-1] * (n + 1) for _ in range(n + 1)]
# 由于本题的客户id不是顺序的,因此这里需要将客户id离散化处理
dic = {}
for i in range(1, n + 1):
idx, dis = map(int, input().split())
# 离散化处理
dic[idx] = i
# 投递站到客户之间的距离distance
dist[0][i] = dis
dist[i][0] = dis
for i in range(1, m + 1):
idx1, idx2, dis = map(int, input().split())
i1 = dic[idx1]
i2 = dic[idx2]
# 客户与客户之间的距离信息
dist[i1][i2] = dis
dist[i2][i1] = dis
# ans记录经过所有点后回到出发点的最短距离
ans = sys.maxsize
# floyd算法求解图中任意两点之间的最短路径
def floyd():
for k in range(n + 1):
for i in range(n + 1):
for j in range(n + 1):
# newDist是经过k后,i->j的距离
newDist = dist[i][k] + dist[k][j]
# 如果newDist是i->j的更短路径
if newDist < dist[i][j]:
# 则更新i->j的最短距离
dist[i][j] = newDist
# 且此更短距离需要经过k, path[i][j]即记录 i->j 最短距离下需要经过点 k
path[i][j] = k
def dfs(pre, sumDis, used, level):
"""
找一条经过所有点的最短路径,我们可以求解所有点形成的全排列,每一个全排列都对应一条经过所有点的路径,只是经过点的先后顺序不同 //
求某个全排列过程中,可以通过dist数组,累计上一个点i到下一个点j的最短路径dist[i][j]
:param pre: 上一个点, 初始为0,表示从披萨店出发
:param sumDis: 当前全排列路径累计的路径权重
:param used: 全排列used数组,用于标记哪些点已使用过
:param level: 用于记录排列的长度
"""
global ans
if level == n:
# 此时pre是最后一个客户所在点,送完最后一个客户后,司机需要回到披萨店,因此最终累计路径权重为 sum + dist[pre][0]
# 我们保留最小权重路径
ans = min(ans, sumDis + dist[pre][0])
return
for i in range(1, n + 1):
if used[i]:
continue
used[i] = True
dfs(i, sumDis + dist[pre][i], used, level + 1)
used[i] = False
# 算法入口
def main():
# floyd算法调用
floyd()
# 全排列模拟经过所有点的路径
dfs(0, 0, [False] * (n + 1), 0)
print(ans)
# 算法调用
main()
C算法源码
#include <stdio.h>
#include <limits.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX_SIZE 11
#define MAX_ID 1000
int n;
int dist[MAX_SIZE][MAX_SIZE];
int path[MAX_SIZE][MAX_SIZE];
int ans;
/**
* 找一条经过所有点的最短路径,我们可以求解所有点形成的全排列,每一个全排列都对应一条经过所有点的路径,只是经过点的先后顺序不同 //
* 求某个全排列过程中,可以通过dist数组,累计上一个点i到下一个点j的最短路径dist[i][j]
*
* @param pre 上一个点, 初始为0,表示从披萨店出发
* @param sum 当前全排列路径累计的路径权重
* @param used 全排列used数组,用于标记哪些点已使用过
* @param level 用于记录排列的长度
*/
void dfs(int pre, int sum, int used[], int level) {
if (level == n) {
// 此时pre是最后一个客户所在点,送完最后一个客户后,司机需要回到披萨店,因此最终累计路径权重为 sum + dist[pre][0]
// 我们保留最小权重路径
ans = MIN(ans, sum + dist[pre][0]);
return;
}
for (int i = 1; i <= n; i++) {
if (used[i]) continue;
used[i] = 1;
dfs(i, sum + dist[pre][i], used, level + 1);
used[i] = 0;
}
}
// floyd算法求解图中任意两点之间的最短路径
void floyd() {
for (int k = 0; k < n + 1; k++) {
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
// newDist是经过k后,i->j的距离
int newDist = dist[i][k] + dist[k][j];
// 如果newDist是i->j的更短路径
if (newDist < dist[i][j]) {
// 则更新i->j的最短距离
dist[i][j] = newDist;
// 且此更短距离需要经过k, path[i][j]即记录 i->j 最短距离下需要经过点 k
path[i][j] = k;
}
}
}
}
}
int main() {
int m;
scanf("%d %d", &n, &m);
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
// 初始时默认i,j不相连,即i,j之间距离无穷大
if (i != j) {
dist[i][j] = INT_MAX;
}
path[i][j] = -1;
}
}
// 由于本题的客户id不是顺序的,因此这里需要将客户id离散化处理
int map[MAX_ID];
for (int i = 1; i <= n; i++) {
int id, dis;
scanf("%d %d", &id, &dis);
// 离散化处理
map[id] = i;
// 投递站到客户之间的距离distance
dist[0][i] = dis;
dist[i][0] = dis;
}
for (int i = 1; i <= m; i++) {
int id1, id2, dis;
scanf("%d %d %d", &id1, &id2, &dis);
int i1 = map[id1];
int i2 = map[id2];
// 客户与客户之间的距离信息
dist[i1][i2] = dis;
dist[i2][i1] = dis;
}
// floyd算法调用
floyd();
// ans记录经过所有点后回到出发点的最短距离
ans = INT_MAX;
// 全排列模拟经过所有点的路径
int used[MAX_SIZE] = {0};
dfs(0, 0, used, 0);
printf("%dn", ans);
}
免责声明:
1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文
评论0