dp基础之序列型最长上升子序列

问题 :给定a[i](i=0...n-1),找到最长上升子序列(假设长度为k),输出k

例:
a = [4,2,4,5,3,7]
返回 
k=4([2,4,5,7])
 

分析:
对于最优策略:一定有最后一个元素a[j]
情况1:最优策略就是{a[j]},长度k就是1
情况2:最优策略子序列长度大于1,则最优策略中最后一个元素a[j]前一定有一个元素a[i],且a[i]<a[j](i<j)
       且以a[i]结尾的序列列也是最优的

子问题:f[i]表示以a[i]结尾的最长子序列长度
    f[i] = max{1,f[i]+1 | i<j && a[i]<a[j] } 
 
计算顺序:
f[0]...f[n-1]

时间复杂度O(n^2) ,空间复杂度O(n)

代码及注释如下:

def long_sequence(a):
    #f[i]表示以a[i]结尾的上升子序列的长度
    n = len(a)
    if n == 0:
        return ;
    f = [0 for j in range(n)]
    #初始,以a[0]结尾的最长上升子序列长度就是1
    for j in range(n):
        #情况1,f[0] = 1
        f[j] = 1
        #枚举j之前最优子序列长度
        for i in range(j):
            if a[i] < a[j] and f[j] < f[i]+1:
                f[j] = f[i] + 1
    return max(f)
a = [4,2,4,5,3,7]
print(long_sequence(a))
#结果:4

信封问题跟这个类似,就放一起比较

问题:给定N个信封的长和宽,如果另一个信封的长和宽更小,则可以被套进信封去,问,最多嵌套多少个信封?

分析:
确定状态:
先考虑长度,将所有信封长度从小到大排序
设:最优策略里最外层信封的长度时Ej,则
    次外层信封的长度Ei,也是最优策略,且Ei<Ej(i<j)

子问题:要知道以Ej结尾的最优策略的长度,则我们需要知道以Ei结尾的最优策略

设f[i]是以Ei为最外层信封的最优策略的信封数
    f[i] = max{i, f[j] + 1 | Ej在Ei里,j<i}

无初始条件

依次求f[0],...,f[n-1]
需要对信封长度排序,时间复杂度O(N^2),空间复杂度O(N)

 

代码及注释如下:

def doll_envelope(E):
    n = len(E)
    if n == 0:
        return 0
    #f[i]是以Ei为最外层信封的最优策略的信封数
    f = [0 for i in range(n)]
    for i in range(n):
        #f[0] = 1
        f[i] = 1
        for j in range(i):
            #前面的长度小且宽度小,信封j可以放到信封i里
            if E[j][0] < E[i][0] and E[j][1] < E[i][1]:
                f[i] = max(f[i],f[j] + 1)
    return max(f)
A = [[5,4],[6,4],[6,7],[2,3]]
E = sorted(A)
print(doll_envelope(E))
#结果:3

未完待续。。。

猜你喜欢

转载自blog.csdn.net/lerry13579/article/details/84109281