• 贪心算法


    一 什么是贪心算法

    贪心算法(又称贪婪算法)是指在对问题求解时,总是做出在当前看来最好的选择。也就是说,不从整体最优上加以考虑他所做出的是某种意义上的局部优解
    贪心算法并不保证会得到最优解, 但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算

    贪心算法每一步必须满足一下条件:

    • 可行的:即它必须满足问题的约束。
    • 局部最优:他是当前步骤中所有可行选择中最佳的局部选择。
    • 不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。

    二 找零问题

    假设商店老板需要找零n元钱, 钱币的面额有:100元 50元 20元 5元 1元,如何找零使得所需钱币的数量最少?

    解决思路:

    • 先用n去整除每张钱币的面额,得到的结果为每张钱币的数量
    • 再用n对钱币取模并将结果赋值给n

    实现代码

    t = [100, 50, 20, 5, 1]  # 钱的面额
    
    def change(t, n):
        m = [0 for _ in range(len(t))]  # 每个面额 找零的数量
        for i, money in enumerate(t):
            m[i] = n // money
            n = n % money
        return m, n
    
    
    print(change(t, 376))

     三 背包问题

    一个小偷在某个商店发现n个商品,第i个商品价值Vi元,重量Wi千克。它希望拿走的价值尽量高,但是他的背部最多能容纳W千克的东西,他应该拿走哪些商品?
    0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次。(商品为金条)
    分数背包: 对于一个商品,小偷可以拿走其中任意一部分(商品为金砂)

    举例:

    商品1:V1=60 W1=10
    商品2:V2=100 W2=20
    商品3:V3=120 W3=30
    背包容量:W=50
    对于0-1背包和分数背包,贪心算法是否能得到最优解?为什么?

    分数背包实现:

    goods = [(60, 10), (100, 20), (120, 30)]  # 每个元素表示(价格,重量)
    goods.sort(key=lambda x: x[0] / x[1], reverse=True)  # 安商品价值排序 倒序
    
    def fractional_backpack(goods, w):
        m = [0 for _ in range(len(goods))]
        total_v = 0
        for i, (price, weight) in enumerate(goods):
            if w >= weight:
                m[i] = 1
                w -= weight
                total_v += price  # 总价值
            else:
                m[i] = w / weight
                w = 0
                total_v += m[i] * price
                break
        return total_v, m
    
    
    print(fractional_backpack(goods, 50))

    四 拼接最大数字问题

    有n个非负整数, 将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?
    例如:32,94,128,1286,6,71 可以拼接的最大整数位94716321286128

    from functools import cmp_to_key
    li = [32, 94, 128, 1286, 6, 71]
    
    def xy_cmp(x, y):
        if x + y < y + x:
            return 1
        elif x + y > y + x:
            return -1
        else:
            return 0
    
    
    def number_join(li):
        li = list(map(str, li))
        li.sort(key=cmp_to_key(xy_cmp))
        return "".join(li)
    
    
    print(number_join(li))

     使用冒泡排序后拼接实现的代码

    li = [32, 94, 128, 1286, 6, 71]
    
    def number_join(li):
        li = list(map(lambda x: str(x), li))
        for i in range(0, len(li) - 1):
            for j in range(0, len(li) - 1 - i):
                if li[j] + li[j + 1] < li[j + 1] + li[j]:
                    li[j], li[j + 1] = li[j + 1], li[j]
            print(li)
    
        return "".join(li)
    
    
    print(number_join(li))

    五  活动选择问题

    假设有n个活动, 这些活动要占用同一片场地,而场地在某时刻只能供一个活动使用
    每个活动都有一个开始时间Si和结束时间Fi(题目中时间以整数表示),表示活动在[Si,Fi)区间占用场地
    问:安排哪些活动能够使该场地举办的活动个数最多


    贪心结论: 最先结束的活动一定是最优解的一部分
    证明:假设a是所有活动中最先结束的活动,b是最优解中最先结束的活动
    如果 a = b 结论成立
    如果 a !=b 则b的结束时间一定晚于a的结束时间, 则此时用a替换掉最优解中的b, a一定不与最优解中的其他活动时间重叠,因此替换后的解也是最优解。

     实现代码:

    activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11), (8, 12), (2, 14), (12, 16)]
    # 保证活动是按照结束时间排好序
    activities.sort(key=lambda x: x[1])
    
    
    def activity_selection(a):
        res = [a[0]]
        for i in range(1, len(a)):
            if a[i][0] >= res[-1][1]:  # 当前活动的开始时间要小于等于最后一个入选活动的结束时间
                # 不冲突
                res.append(a[i])
        return res
    print(activity_selection(activities))
  • 相关阅读:
    DOM操作:
    定时器
    7.thinkphp框架控制器
    1.thinkphp框架介绍
    4.thinkphp框架url访问
    6.thinkphp框架路由
    2.thinkphpk框架基础
    5.thinkphp框架配置文件
    3.thinkphp框架入口文件
    8.thinkphp框架数据库
  • 原文地址:https://www.cnblogs.com/harryblog/p/10715365.html
Copyright © 2020-2023  润新知