贪婪算法

复习一下贪婪算法。

个人的记忆和理解是:每一步都选择局部最优解。贪婪算法只是一种求得“近似”最优解的算法,并不能保证最终结果是最优解。

这里模仿《算法图解》中的广播覆盖问题模仿提出一个问题。(上述链接提取码为q0m8)

题:现有9个集合,每个集合中各有几个10以内的自然数,现要求尽量用到少的集合凑齐1-10的所有数

假如有这么几个集合:

a {1, 10, 4, 7}
b {10, 3, 4, 6}
c {3, 4, 5, 7}
d {8, 4, 5}
e {9, 10, 3, 6}
f {8, 5, 7}
g {8, 10, 3, 6}
h {1, 3, 4}
i {8, 1, 3, 5}
j {1, 2, 3, 6}

要用到最少的集合凑齐1到10这些数字,想要把所有可行组合都算出来是一个相当艰难的事情,当然在当前题目下,还是可以花费时间做到的,但是一旦此题的集合数与需要凑齐的数值范围大了以后,计算量就大到代价不能承受的地步了。

这种情况下,只能一步一步,每一步都尽可能凑齐最多的需要的数字,直到所有数字都凑齐,这样得到的最终结果或许不是最优的,但已经接近最优解,并且所花费代价比得到精确的最优解要小得多。综合上来说,这就是”最优解“,这就是贪婪算法。

选出的集合为a--{1, 10, 4, 7},还剩下{2, 3, 5, 6, 8, 9}未得到
选出的集合为e--{9, 10, 3, 6},还剩下{8, 2, 5}未得到
选出的集合为d--{8, 4, 5},还剩下{2}未得到
选出的集合为j--{1, 2, 3, 6},已全部得到

据此策略,我们需要一个”得到局部最优解“的算法去得到当前这一步的最佳选择。
在所有还未被选择的集合中,能凑到最多数字(没有凑到的数字)的集合,就是当前的最优解。

以此分析上面的集合:

  1. 因为尚未凑到任何一个数,所有第一步只要凑到最多的数字就行了,于是得到了{1, 10, 4, 7}这个集合,当然其他几个长度为4的集合也是当前的最优解之一
  2. 第一步过后,还剩下{2, 3, 5, 6, 8, 9}这些数字需要凑,那么需要找到能凑到最多这些数字的集合才行,这一步也有{9, 10, 3, 6}和{8, 10, 3, 6}、{8, 1, 3, 5}、{1, 2, 3, 6}这些选择,因为都可以凑到3个数,但因为顺序关系,选择了{9, 10, 3, 6}
  3. 这一步还剩下{8, 2, 5}这些数字要凑,这一步有{8, 4, 5}、{8, 5, 7}、{8, 1, 3, 5}可以选择,因为都可以凑到2个数,同上面的原因选择了{8, 4, 5}
  4. 最后需要凑到{2},这一步只有{1, 2, 3, 6}可以选择

用python写了一个随机生成例子来解释贪婪算法。
其中寻找当前最优解的方法是这样的:

def find_best_candidate_set(dict_nums, nums):
    """
    选出当前所有集合中,可得到最多‘可用’数字的一个集合(key)
    :param dict_nums: 待筛选的集合字典
    :param nums: 用于筛选的数字集合
    :return: 筛选出的key
    """
    best_coverd = set()  # 最佳的数字集合
    best_coverd_key = None  # 最佳的集合所对应的key
    for k, v in dict_nums.items():
        temp_coverd = nums & v  # 当前此集合能得到的数字集合
        if len(temp_coverd) > len(best_coverd):
            best_coverd = temp_coverd
            best_coverd_key = k
    return best_coverd_key

在python中,两个set交集可以直接使用“&”符号获得,差集也可使用“-”符号获得。类似于Java中的listA.retains(listB)/listA.removeAll(listB)之类的操作。

全部代码见greedy.py

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值