01背包问题作为著名的动态规划问题之一,在算法学习中的意义不言而喻。
最近刷到一道题,在01背包问题中有稍微改变。
题中不仅要求输出最大概率之和,还要求输出楼盘ID。
动态规划问题
例如输入序列为:
5 10
2 0.2
3 0.3
4 0.44
5 0.55
6 0.6
贪心算法:
第一种解法是贪心算法
- 将所有楼盘序列计算出单位概率。
- 按照单位概率将序列排序。
- 依次从高概率遍历到低概率,从而得到局部最优解。
算法代码:
1 | def greedy(): |
我们可以得到结果
0.99 [4, 3]
显然这不是我们想要的结果,因为最优解应该为1,2,4 = 1.05才对。
动态规划
寻找最大概率值
使用动态规划的方法解决该问题需要对问题建立转移方程:
输入楼盘数量为number,总资金为fund
输入楼盘的数据raw_data.
定义子问题P(i, v)为在前i个楼盘中挑选总价值不超过v的楼盘,并且每个楼盘只能选择一次,使得最终抽中的总概率最大。我们此时的最优解记作max_prob(i, w),其中1<=i<=number,1<=w<=fund。
当我们考虑第i个楼盘的时候:
如果不选择,则总资金容量不变,改为问题P(i-1, w)
如果选择这个楼盘,则总资金剩余容量变小,改问题为P(i-1, w-wi)
最优解的问题就是比较3中两个方案哪一个是最佳的:
max_prob(i,w) = max{max_prob(i-1,w),max_prob(i-1,w-wi)+valuei}
例如输入序列为:
5 10
2 0.2
3 0.3
4 0.44
5 0.55
6 0.6
假设我们一共有10W金钱,楼盘价值分别为2,3,4,5,6。楼盘概率分别为0.2,0.3,0.44,0.55,0.6。
那么我们通过转移方程可以推算出以下表格max_prob:
推算过程:
建立一个表格,大小为number×fund。
逐层遍历,按列遍历。
当资金为1的时候,没有任何房产可以购买。
当资金为2的时候,可以购买房产1。
当资金为3的时候,可以购买房产1,但是当遍历到(2,3)的时候,对比
max{max_prob(i-1,w),max_prob(i-1,w-wi)+valuei}
其中max_prob(i-1,w) 代表i-1行w列。
其中max_prob(i-1,w)为0.2,max_prob(i-1,w-wi)+valuei 为0.2-0.2 + 0.3 = 0.3
经过逐次的遍历,得到最终整个矩阵数据。
算法代码:
1 | def dynasty(): |
计算楼盘的序列
定义指针(i,j)倒序遍历表格
从末尾开始遍历,寻找按顺序排列第一次出现
all_max
节点,将all_max
修改为all_max-raw_data[i][prob]
当找到第一个星号1.05后移动指针位置到(i-1,j-1),检测当前值是否为第一次出现的
all_max
,如果是,标记为星,并重复2步骤,直到遍历到(0,0)输出所有标记星所在的行即为楼盘序列。
算法代码:
1 | # ----------------从表中推出楼盘列表-------------- |
算法源码点击 这里
引用: