题目
附图中有一个无向图,其中圈内数字代表一个地点,边e上数字代表长度Le(双向相同)。
一位外卖小哥在起点A,要去3个商家(B1, B2, B3)取餐,送到3个对应的地方(C1, C2, C3),即B1至C1,B2至C2,B3至C3。
小哥的电动助力车的箱子同时最多装下2份外卖。
请问: 小哥该怎么走最短路径?这个最短路径的长度是多少?
这里,A是出发点,最后一餐(不限次序)送达地为终点。
为了简化问题,假设商家已经备好了外卖,小哥取餐送餐不用等。又假设每份外卖重量大小一样。
附图:
解答
import copy
points_graph = {
'1': {
'2': 1,
'5': 1
},
'2': {
'1': 1,
'3': 2,
'6': 2
},
'3': {
'2': 2,
'4': 1,
'8': 2
},
'4': {
'3': 1,
'15': 3
},
'5': {
'1': 1,
'6': 1,
'9': 1
},
'6': {
'2': 2,
'5': 1,
'7': 1
},
'7': {
'6': 1,
'8': 1,
'10': 1
},
'8': {
'3': 2,
'7': 1,
'11': 1
},
'9': {
'5': 1,
'10': 3,
'12': 2
},
'10': {
'7': 1,
'9': 3,
'11': 1,
'13': 2
},
'11': {
'8': 1,
'10': 1,
'14': 1
},
'12': {
'9': 2,
'13': 2
},
'13': {
'10': 2,
'12': 2,
'14': 1
},
'14': {
'11': 1,
'13': 1,
'15': 1
},
'15': {
'4': 3,
'14': 1
},
}
b_points = {
'3': 'B1',
'7': 'B2',
'4': 'B3'
}
c_points = {
'12': 'C1',
'11': 'C2',
'13': 'C3'
}
most_orders = 2
def point_travel(point_current, distance_current, orders_get, orders_finish, travel_history):
"""
point_current: 所在位置,
distance_current: 已走路径距离,
orders_get: 手中有什么外卖,
orders_finish: 已完成订单,
travel_history: 路径集
"""
# 订单是否都已完成
if len(orders_finish) == len(c_points):
if distance_current in distance_travel:
distance_travel[distance_current].append(travel_history)
else:
distance_travel[distance_current] = [travel_history]
return None
# 当计算完一个distances时,只考虑比当前distances小的走法
if len(distance_travel) > 0:
if distance_current >= min(distance_travel.keys()) - 1:
return None
# next step
for key, value in points_graph[point_current].items():
# 当next step点的状态已存在时,continue
if (key, orders_get, orders_finish) in travel_history:
continue
distances_ = distance_current
distances_ += value
travel_history_ = travel_history.copy()
orders_get_ = orders_get.copy()
if key in b_points:
# 当前为商家
if len(orders_get) < most_orders and b_points[key] not in orders_get and b_points[key].replace('B', 'C') not in orders_finish:
# 在商家点,当箱子未满时且当前商家外卖未装箱且当前商家订单未完成,小哥可选是否将外卖装箱
for i in range(2):
travel_history_ = travel_history.copy()
if i:
orders_get_.add(b_points[key])
travel_history_.append((key, orders_get_, orders_finish))
point_travel(key, distances_, orders_get_, orders_finish, travel_history_)
else:
# 当前商家不装箱
travel_history_.append((key, orders_get_, orders_finish))
point_travel(key, distances_, orders_get_, orders_finish, travel_history_)
elif key in c_points:
# 当前为客户
order = c_points[key].replace('C', 'B')
orders_finish_ = orders_finish.copy()
# 有当前客户的外卖,就结束订单
if order in orders_get:
orders_get_.remove(order)
orders_finish_.add(c_points[key])
travel_history_.append((key, orders_get_, orders_finish_))
point_travel(key, distances_, orders_get_, orders_finish_, travel_history_)
else:
# 更新路径
travel_history_.append((key, orders_get, orders_finish))
# 转入下一个位置动作
point_travel(key, distances_, orders_get, orders_finish, travel_history_)
return None
if __name__ == '__main__':
distance_travel = {}
point_travel('2', 0, set(), set(), [])
min_distance = min(distance_travel.keys())
print(min_distance)
for travel in distance_travel[min_distance]:
print(travel)
16
16
[('6', set(), set()), ('7', {'B2'}, set()), ('8', {'B2'}, set()), ('11', set(), {'C2'}), ('8', set(), {'C2'}), ('3', {'B1'}, {'C2'}), ('4', {'B1', 'B3'}, {'C2'}), ('15', {'B1', 'B3'}, {'C2'}), ('14', {'B1', 'B3'}, {'C2'}), ('13', {'B1'}, {'C2', 'C3'}), ('12', set(), {'C1', 'C2', 'C3'})]
[('6', set(), set()), ('7', {'B2'}, set()), ('10', {'B2'}, set()), ('11', set(), {'C2'}), ('8', set(), {'C2'}), ('3', {'B1'}, {'C2'}), ('4', {'B1', 'B3'}, {'C2'}), ('15', {'B1', 'B3'}, {'C2'}), ('14', {'B1', 'B3'}, {'C2'}), ('13', {'B1'}, {'C2', 'C3'}), ('12', set(), {'C1', 'C2', 'C3'})]