OD C卷 - 快递员的烦恼

快递员的烦恼(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)


 

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值