动态规划

外卖小哥的保温箱

http://www.nowcoder.com/questionTerminal/f3826b317d094e17a04e64a402bd0866

这道题整了一晚上,最后看大佬@Albert7 代码思考人生,才想出来怎么做,现在分享一下菜鸡思路
博客链接https://blog.csdn.net/qq_28597451/article/details/104691882
昨天在牛客网上做笔试题,碰到了一道题动态规划做了一晚上都没做出来,最后看着别人的答案才勉强做出来,太菜了,今天总结一下。

动态规划思路:
1、找到状态和选择,确定当前状态和转换
2、明确dp数组/或函数的定义,即dp数组保存了啥信息(dp数组一般是一维或二维)
3、寻找状态之间的关系,当前状态如何根据上一状态和一些已知信息得到(状态转换方程)

下面是解题思路

从题目可以了解到,我们需要做的是:
1、找出需要的最少的k个保温箱,使得这个k个保温箱可以装下所有的货物;
2、确定转移货物的最少时间,所以所找到的k个保温箱中所包含的货物尽可能多,则需要转移货物就越少,时间越短;

输入代码:

import sys
inp = []
while True:
    line = sys.stdin.readline().strip()
    if line == '':
        break
    line = (line.split(' '))
    inp.append([int(line[i]) for i in range(len(line))])
n = inp[0][0]
food = inp[1]
capacity = inp[2]

上面的输入莫名奇妙就爆bug了,通过不了,大概可能是原来是牛客网的输入可能混杂了空行或者为空,所以输入就出错误了,以后注意点。下面是正确(可以通过的)读取输入代码

import sys
n = int(input().strip())
lines = sys.stdin.readlines()
if len(lines) == 1:
    temp = list(map(int, lines[0].strip().split()))
    food = temp[:n]
    capacity = temp[n:]
else:
    food = list(map(int, lines[0].strip().split()))
    capacity = list(map(int, lines[1].strip().split()))
max_food = sum(food)
max_capacity = sum(capacity)

1、定义一个dp[capacity][2]数组,dp[i] = [k,food] 保存总容量为i的保温箱最少可以由k个保温箱组成,而且保温箱原来的总货物为food,应该是最大的;并初始化k的值为最大值(保温箱的数目)然后一步一步减小
2、转换方程:因为我们要保证使用的保温箱是最少的,对于第k个保温箱,当前最大容量为i,它是由容量max(i-capacity[k-1], 0)来决定的,

for k in range(1, n+1): # 对于每一个保温箱
    for i in range(max_capacity, 0, -1): # 对于当前容量最大的,从最大容量倒序
        count = dp[max(i - capacity[k-1], 0)][0]
        weight = dp[max(i - capacity[k-1], 0)][1]
        if dp[i][0] < count+1:  # 保证当前所需要的保温箱最少
            continue
        elif dp[i][0] > count+1:   # 比当前所需要的保温箱少,更新当前所选择保温箱数,货物数为之前加上当前保温箱的货物,不用比较大小,因为所需保温箱数比之前少,优先级更高
            dp[i][0] = count + 1
            dp[i][1] = weight + food[k-1]
        else: # 两者相等,取最大值
            dp[i][1] = max(weight + food[k - 1], dp[i][1])

3、寻找最优值,找到从大于等于当前货物数的容量区间[max_food, max_capacity]中,从需要箱子最少中找出货物最多的

min_step = 0
min_bin = n
for i in range(max_food, max_capacity+1):
    if dp[i][0] < min_bin:
        min_bin = dp[i][0]
        min_step = dp[i][1]
    elif dp[i][0] == min_bin:
        min_step = max(dp[i][0], min_step)
min_step = max_food - min_step

总的代码

import sys
n = int(input().strip())
lines = sys.stdin.readlines()
if len(lines) == 1:
    temp = list(map(int, lines[0].strip().split()))
    food = temp[:n]
    capacity = temp[n:]
else:
    food = list(map(int, lines[0].strip().split()))
    capacity = list(map(int, lines[1].strip().split()))

max_food = sum(food)
max_capacity = sum(capacity)
dp = [[len(food), 0] for _ in range(max_capacity+1)]
dp[0] = [0, 0]

for k in range(1, n+1):
    for i in range(max_capacity, 0, -1):
        count = dp[max(i - capacity[k-1], 0)][0]
        weight = dp[max(i - capacity[k-1], 0)][1]
        if dp[i][0] < count+1:
            continue
        elif dp[i][0] > count+1:
            dp[i][0] = count + 1
            dp[i][1] = weight + food[k-1]
        else:
            dp[i][1] = max(weight + food[k - 1], dp[i][1])
print(dp[:][:])

min_step = 0
min_bin = n
for i in range(max_food, max_capacity+1):
    if dp[i][0] < min_bin:
        min_bin = dp[i][0]
        min_step = dp[i][1]
    elif dp[i][0] == min_bin:
        min_step = max(dp[i][0], min_step)
min_step = max_food - min_step
# print(max_food, min_step)
print(str(min_bin) + ' ' + str(min_step))
全部评论
就应该从总货物倒序,我觉得。这样复杂度还小些
点赞 回复 分享
发布于 2020-03-27 11:27
为什么要从最大容量(sum(b))倒序而不是从总货物数(sum(a))倒序呢
点赞 回复 分享
发布于 2020-03-12 00:33

相关推荐

头像
10-13 18:10
已编辑
东南大学 C++
。收拾收拾心情下一家吧————————————————10.12更新上面不知道怎么的,每次在手机上编辑都会只有最后一行才会显示。原本不想写凉经的,太伤感情了,但过了一天想了想,凉经的拿起来好好整理,就像象棋一样,你进步最快的时候不是你赢棋的时候,而是在输棋的时候。那废话不多说,就做个复盘吧。一面:1,经典自我介绍2,项目盘问,没啥好说的,感觉问的不是很多3,八股问的比较奇怪,他会深挖性地问一些,比如,我知道MMU,那你知不知道QMMU(记得是这个,总之就是MMU前面加一个字母)4,知不知道slab内存分配器-&gt;这个我清楚5,知不知道排序算法,排序算法一般怎么用6,写一道力扣的,最长回文子串反问:1,工作内容2,工作强度3,关于友商的问题-&gt;后面这个问题问HR去了,和中兴有关,数通这个行业和友商相关的不要提,这个行业和别的行业不同,别的行业干同一行的都是竞争关系,数通这个行业的不同企业的关系比较微妙。特别细节的问题我确实不知道,但一面没挂我。接下来是我被挂的二面,先说说我挂在哪里,技术性问题我应该没啥问题,主要是一些解决问题思路上的回答,一方面是这方面我准备的不多,另一方面是这个面试写的是“专业面试二面”,但是感觉问的问题都是一些主管面/综合面才会问的问题,就是不问技术问方法论。我以前形成的思维定式就是专业面会就是会,不会就直说不会,但事实上如果问到方法论性质的问题的话得扯一下皮,不能按照上面这个模式。刚到位置上就看到面试官叹了一口气,有一些不详的预感。我是下午1点45左右面的。1,经典自我介绍2,你是怎么完成这个项目的,分成几个步骤。我大致说了一下。你有没有觉得你的步骤里面缺了一些什么,(这里已经在引导我往他想的那个方向走了),比如你一个人的能力永远是不够的,,,我们平时会有一些组内的会议来沟通我们的所思所想。。。。3,你在项目中遇到的最困难的地方在什么方面4,说一下你知道的TCP/IP协议网络模型中的网络层有关的协议......5,接着4问,你觉得现在的socket有什么样的缺点,有什么样的优化方向?6,中间手撕了一道很简单的快慢指针的问题。大概是在链表的倒数第N个位置插入一个节点。————————————————————————————————————10.13晚更新补充一下一面说的一些奇怪的概念:1,提到了RPC2,提到了fu(第四声)拷贝,我当时说我只知道零拷贝,知道mmap,然后他说mmap是其中的一种方式,然后他问我知不知道DPDK,我说不知道,他说这个是一个高性能的拷贝方式3,MMU这个前面加了一个什么字母我这里没记,别问我了4,后面还提到了LTU,VFIO,孩子真的不会。
走呀走:华子二面可能会有场景题的,是有些开放性的问题了
点赞 评论 收藏
分享
评论
8
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务