快递员的烦恼(200)
- 保证快递送到客户手中,不限制先后顺序;
- 所有快递送完后,快递员还需要回到投递站(只有一个);
- 投递站与客户之间都有路线,但客户与客户之间不一定有路线;投递站、客户位置均允许多次经过;
输入描述:
首行输入两个正整数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-客户2-投递站 2500
路径2,投递站-客户2-客户1-投递站 2500
路径3,投递站-客户1-投递站-客户2-投递站4400
示例2:
输入:
5 1
5 1000
9 1200
17 300
132 700
500 2300
5 9 400
输出:
9200
思路:
-
BFS 遍历图,使用邻接矩阵表示图的关联(距离);
-
客户的id不一定是从1->n的连续整数,所以需要映射到1->n;
-
一个客户有两种状态(已访问、未访问),n个客户有 2 n 2^n 2n种状态,n最大为10,所以最多 2 10 = 1024 2^{10}=1024 210=1024中状态;以客户id为列(从0开始,0为投递站),以每种状态为行,得到状态矩阵,广度优先遍历状态矩阵;
-
最后一种状态(2^n -1 行,0列)即为最短距离;
# 输入n m n表示客户数 m 表示查询的路线
n, m = [int(x) for x in input().split()]
# (n + 1) * (n + 1) 邻接矩阵 顶点的关联(通过输入的距离 确定连通性)
matrix = [[float('inf') for i in range(n + 1)] for j in range(n + 1)]
# 客户 id 映射
# 防止客户id 不是1 - n的连续值
cid_map = [0 for _ in range(2000)]
# ****************更新matrix邻接矩阵*********************
# 输入 n 行数据
for i in range(n):
cid, distance = [int(x) for x in input().split()]
# 真实的客户id作为索引,映射的客户id作为值
cid_map[cid] = i + 1 # 映射到1-n的连续值
# 0 表示投递站,投递站与当前客户(映射后的id)的距离
matrix[0][i + 1] = distance
matrix[i + 1][0] = distance # 邻接矩阵是对称阵
# 输入m行 快递员自己查询的 距离
for i in range(m):
cid1, cid2, distance = [int(x) for x in input().split()]
# matrix 对称阵
matrix[cid_map[cid1]][cid_map[cid2]] = distance
matrix[cid_map[cid2]][cid_map[cid1]] = distance
# ****************更新matrix邻接矩阵*********************
# ****************状态矩阵的广度优先遍历*********************
# 保存客户访问状态 0表示投递站
# 因为有n个客户,所以最多有2的n次方个状态
# n最大为10, 所以最多1024个状态
cache = [[float('inf') for i in range(n + 1)] for j in range(1024)]
# 当前访问的客户状态以及距离
queue = []
queue.append([0, 0]) # [初始状态,客户映射id] 0表示投递站 1 2 3 .. 表示客户的映射id
# 投递站的初始状态 距离为0
cache[0][0] = 0
while True:
if len(queue) <= 0:
break
else :
pre_state, pre_cid = queue.pop(0)
# 从当前position出发,到所有的客户
i = 0 # 客户id 0 表示为投递站
while True:
if i > n: # 大于最大客户id
break
else:
# 出发点 走向 -> i 客户, 但i不能自己走向自己
# 若i是出发点 或者 两客户之间没有路线 则跳过
if i == pre_cid or matrix[pre_cid][i] == float('inf'):
i += 1 # 走向下一个客户
continue
# 新状态
new_state = pre_state
if i > 0: # 到达真实客户时,才更新状态
new_state = pre_state | pow(2, i-1) #
if cache[new_state][i] > cache[pre_state][pre_cid] + matrix[pre_cid][i]:
# 当前状态下 对应客户i的距离
cache[new_state][i] = cache[pre_state][pre_cid] + matrix[pre_cid][i]
# 追加当前 [状态,客户]
queue.append([new_state, i])
i += 1
# ****************状态矩阵的广度优先遍历*********************
# 打印状态 矩阵
for i in range(2**n):
print("cache[%d]:" % i, cache[i])
# 输出最短距离
final_distance = cache[pow(2, n) - 1][0]
if final_distance == float('inf'):
print(-1)
else :
print(final_distance)