dp基础之序列型House Robber

问题:有一排房子N栋,房子i 里有金币 house[i],现有小偷想选择而一些房子偷金币,为了防止被抓,不能偷相邻两栋房子,问最多能偷多少钱?

分析;
在最优策略中,偷或不偷房子N-1
    1不偷,则最优策略就是前N-1栋房子的最优策略
    2偷,需要知道前N-1栋房子的最优策略且房子N-2不能偷。

子问题:
我们用f[i][0]表示在不偷房子i-1的情况下,前i-1栋房子的最优策略(即获得最多金币),f[i][1]表示偷房子i-1情况下前i-1栋房子的最优策略,则
    f[i][0] = max{f[i-1][0],f[i-1][1]}
    不偷房子i-1的最多金币 = 所以房子i-2可以选择偷或不偷,两者取最大值
    f[i][1] = f[i-1][0] + house[i-1]
    偷房子i-1的得到最多金币 = 不偷房子i-2的最多金币+房子i-1的金币
   
对于上面不偷房子i-1即f[i][0],其实即等于前i-2栋的最优策略即f[i-1],就是f[i][0] = f[i-1]

故只需用f[i]表示窃贼在前i栋房子得到的最多金币数
 
f[i]= max{f[i-1],f[i-2]+house[i-1]} 

窃贼在前i栋房子得到的最多金币数 = max{不偷房子i-1得到最多的金币(即在前i-1栋房子的最优策略);(偷房子i-1)窃贼在前i-1栋房子的得到的最多金币+偷房子i-1} 

初始条件:
f[0] = 0(没有房子,偷0金币)
f[1] = house[0]

f[2] = max{f[1],f[0]+house[1]}
.
.
.
f[n]
时间复杂度O(N),空间复杂度为O(1)

 

代码及注释如下:
 

def house_robber(house):
    #其实空间只要虚O(1),用两个变量代替f[i-1]和f[i-2]即可
    n = len(house)
    if n==0:
        return 0
    f = [0 for i in range(n+1)]
    #初始化
    f[0],f[1] = 0,house[0]
    
    for i in range(2,n+1):
        f[i] = max(f[i-1],f[i-2]+house[i-1])
    return f[n]
house = [3,1,6]
print(house_robber(house))
结果为:9

 

若上问题改为房子不是一排,而是一圈,求最多获取的金币?

若房子不是一排,而是一圈,作何解?

分析:如果房子是一圈,则分情况讨论
a:若房子0没被偷,则房子N-1不需要考虑房子0,只需考虑房子N-2,跟前面的原问题情况一样,只不过问题不是从0到N-1,而是直接从房子1到n-1
b:若房子N-1没被偷,说明房子N-1也可以忘记,则直接从0到N-2

最后再取两者的最大值即可

你可能感兴趣的:(动态规划专解)