PAT1 1018 Public Bike Management

题目链接
我的github

题目大意

杭州有很多共享单车服务点,这些点可以借车也可以还车。还有一个共享单车管理点(PBMC)负责管理每个服务点
这个点不能借车也不能还车,现在规定一个每个服务点的最大容量 C C C m a x max max , 如果每个服务点的当前车的数量为最大容量的一半就是最佳状态,如果有一个服务点( S p S_p Sp)的车的数量达到最大或者为0,那么PBMC会去拿走或携带一些车去调整 S p S_p Sp达到最佳状态,同时从PBMC到 S p S_p Sp上的所有服务点都会被调整至最佳状态。
现在需要找出这样一条路使PBMC到 S p S_p Sp的路程最短,假如有多条,则选择需要携带的车的数量最小的一条,如果还是有多条,就选择拿走车的数量最小的一条。输入保证满足条件的答案的唯一性

输入

每组包含一个测试用例,每个用例的第一行是四个数字: C C C m a x max max ( ≤ 100 \leq 100 100, 且总是偶数), N N N( ≤ 500 \leq 500 500, 服务点的数量), S p S_p Sp(所有服务点被编号为1~ N N N,PBMC被编号为0), M M M(路的数量)。第二行是1~ N N N个点的当前车的数量。之后有 M M M行,每行有3个数字 a , b , c a, b, c a,b,c表示 a a a点和 b b b点之间的路程是 c c c

输出

对每个测试样例,在一行之中输出结果。先输出PBMC出发时需要携带的车的数量,在一个空格后输出路径( 0 − > S 1 − > S 2 − > . . . − > S p 0->S_1->S_2->...->S_p 0>S1>S2>...>Sp), 再在一个空格后输出PBMC返回时需要拿走的车

样例输入

10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1

样例输出

3 0->2->3 0

解析

题意中有几点要注意:

  • 可以从路径中的服务点拿车放到另外的服务点,但是只能从先遇到的服务点拿到后遇到的
  • 管理人员从 S p S_p Sp返回的时候不会做任何操作

这一题一开始很容易想到dijkstra,然后又要输出路径,所以就想到保存遍历的最短路径上每一个点的前驱。
这样就等于找到了所有的最短路径,最后还要找出符合条件的唯一一条,所以可以在dfs时进行判断

INF = 0xffffffff
cmax, n, sp, m = 0, 0, 0, 0
edge = list()   #存放边
minneed, minback = INF, INF #最小的携带量和拿走量
pre = list()    #存放每个点的前驱
dis = list()    #存放每个点到PBMC的距离
weight = list() #存放每个点的车的数量-cmax//2
ans, temp = list(), list()  #符合要求的路径,临时路径


def dfs(node):
    global temp, weight, pre, minneed, minback, ans
    temp.append(node)
    if node == 0:   #表示已经找到一条最短路径
        need, back = 0, 0
        for i in range(len(temp) - 2, -1, -1):
            if weight[temp[i] - 1] > 0:
                back += weight[temp[i] - 1]
            else:
                if weight[temp[i] - 1] + back >= 0:
                    back += weight[temp[i] - 1]
                else:
                    need = need - (back + weight[temp[i] - 1])
                    back = 0
        if need < minneed:  #更新要求的路径
            minneed = need
            minback = back
            ans = list(temp)
        elif need == minneed and back < minback:
            minback = back
            ans = list(temp)
        temp.pop()
        return
    else:
        for i in range(len(pre[node])):
            dfs(pre[node][i])
    temp.pop()
    return


def solve():
    global cmax, n, sp, m, weight, dis, pre, minneed, minback, ans
    cmax, n, sp, m = map(int, input().split())
    vis = [False for i in range(n + 1)]
    edge = [[INF for i in range(n + 1)] for j in range(n + 1)]
    weight = list(map(int, input().split()))
    for i in range(n):
        weight[i] = weight[i] - cmax // 2   #方便计算和判断
    for i in range(m):
        a, b, c = map(int, input().split())
        edge[a][b] = edge[b][a] = c
    dis = [INF for i in range(n + 1)]
    dis[0] = 0
    pre = [[] for i in range(n + 1)]
    for i in range(n + 1):  #dijkstra找最短路径和路径的前驱
        mark, mindis = -1, INF
        for j in range(n + 1):
            if (not vis[j]) and dis[j] < mindis:
                mark = j
                mindis = dis[j]
        if mark == -1:
            break
        vis[mark] = True
        for j in range(n + 1):
            if not vis[j]:
                if dis[mark] + edge[mark][j] < dis[j]:
                    dis[j] = dis[mark] + edge[mark][j]
                    pre[j].clear()
                    pre[j].append(mark)
                elif dis[mark] + edge[mark][j] == dis[j]:
                    pre[j].append(mark)
    dfs(sp)
    print("%d 0" % minneed, end="")
    for i in range(len(ans) - 2, -1, -1):
        print("->%d" % ans[i], end="")
    print(" %d" % minback)


if __name__ == "__main__":
    solve()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值