码迷,mamicode.com
首页 > 其他好文 > 详细

DataWhale 动态规划DP

时间:2019-01-09 21:49:19      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:minimum   min   代码   tco   max   .com   mini   turn   两种   

0-1背包问题

问题:有n个物品,第i个物品价值为vi,重量为wi,其中vi和wi均为非负数,背包的容量为W,W为非负数。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。

针对这个经典的动态规划问题,先建立一个实例,如下表格:

物体编号i 1 2 3 4 5
价值v 4 5 10 11 13
重量w 3 4 7 8 9

假设约束条件背包的最大承重\(W = 17\),且每个物体只能装一次,请问背包应该怎么装最好。

这一类问题依旧是两个关键:1.初始条件或者最小子问题最优解;2.递归定义式或状态转移方程。

这里最小子问题最优解应该就是,背包只选一个物品且在限定承重 W‘ 时所指向的最佳物体。这里 W‘ 可以为大于等于1的任意值。

那么状态转移方程应该就是,在当前给定限定承重条件下,从不同的承重组合选出一个最优解(每一个都是它在限定承重条件下得到的最优解)。用数学定义式可以如下:

\[ dp[i][j] = max(dp[i-1][j], dp[i-1][j-w(k)]+v[k]) \]

其中dp[i][j]表示i件物品放入一个容量为j的背包可以获得的最大价值。这个式子不是很好理解,举个例子就很清楚了,如下。

比如当前背包容量是10,那我们可以有多种分配组合,比如9+1,以及7+3。其中dp[i-1][j]可以对应分配的9,dp[i-1][j-w(k)]可以对应分配的7;左边9所对应的1是再找不出适合装的东西了,右边7对应的3可以再装一个编号1。这个式子的意义就是,比较这两种组合其中的更佳者。

需要注意的是,不一定永远是右边的更佳,有时候空间不全部利用反而能得到更加解。这就是动态规划的关键

要是直接将动态规划的代码写出来,有时候可能很困难。可以先考虑用递归做,再将自顶向下的递归转化为自底向上的动态规划就好了。这里就不管这些,直接给出动态规划的代码了。

class ZeroByOnePack:
    def __init__(self, list_v, list_w):
        self.list_v = list_v
        self.list_w = list_w

    def dpPack(n, max_w):
        V = self.list_v
        W = self.list_w
        dp = [0] * (max_w + 1) # 为了形式上好理解,只好浪费一部分空间
        for i in range(n);
            for j in range(W[i], max_w + 1):
                dp[j] = max(dp[j], dp[j-W[i]]+V[i])
        return dp[max_w]                

这里只用一维数组,节省内存空间。

leetcode 132

技术分享图片

技术分享图片

代码实现

作业限制了用动态规划,但其实这道题不用动态规划也可以做。

class Solution(object):
    def minCut(self, s):
        """
        :type s: str
        :rtype: int
        """
        cut = [x for x in range(-1,len(s))]
        for i in range(0,len(s)):
            for j in range(i,len(s)):
                if s[i:j] == s[j:i:-1]:
                    cut[j+1] = min(cut[j+1],cut[i]+1)
        return cut[-1]

当然,这个性能是很差的,时间复杂度应该达到了O(n^3)?如果用动态规划的话,时间复杂度只要O(n^2)。

class Solution:
    def minCut(self, s):
        """
        :type s: str
        :rtype: int
        This can be solved by:
        
        cut[end] is the minimum of cut[st-1] + 1 (st <= end) if [st, end] is palindrome
        
        a   b   a   |   c    c
                        st  end
               st-1 |  [st,  end] is palindrome
          cut(st-1) +  1
          
        """
        n = len(s)
        cut = [0] * n
        pal = [[False] * n for row in range(n)]
        
        for end in range(n):
            min_cut = end
            for st in range(end + 1):
                if s[st] == s[end] and (end - st <= 2 or pal[st+1][end-1]):
                    pal[st][end] = True
                    min_cut = 0 if st == 0 else min(min_cut, cut[st-1] + 1)
            cut[end] = min_cut
        
        return cut[n-1]

代码不是自己写的。我只能根据简单的思路写出递归的算法,但是这道题卡了递归的边界。也许将递归算法改进成备忘录方法会更好点,这个留待以后验证了。

DataWhale 动态规划DP

标签:minimum   min   代码   tco   max   .com   mini   turn   两种   

原文地址:https://www.cnblogs.com/ChanWunsam/p/10246615.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!