笔试刷题 | 贪心算法

定义

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即个状态以前的过程不会影响以后的状态,只与当前状态有关

个人疑惑

这句话能否在现实生活中使用?

因为生活中常常接触的道理是不能短视,要有大局观,牵一发而动全身,不能为了一点蝇头小利而失去自我。

而贪心算法都是基于当前做一个最优选择,以及它的前提是当前状态不影响以后状态,这个前提怎么能做到呢?因为,我们生活中的得失都是之前做出的决断共同造就的呀。

不过,贪心算法并不一定能得到全局最优解,这是肯定的。

#! /usr/bin/env python
# -*-coding:utf-8-*-
"""
Author: ChileWang
Created at 2020/03/20 15:59


Question:
贪心算法
常用于处理一维度问题,所得的解并不一定是最优解
贪心算法的每一次操作都对结果产生直接影响,而动态规划则不是。
贪心算法对每个子问题的解决方案都做出选择,不能回退;


动态规划则会根据以前的选择结果对当前进行选择,有回退功能。
动态规划主要运用于二维或三维问题,而贪心一般是一维问题 。
"""
import random




def horse_competition():
    n = int(input("输入马匹数目:"))
    tj = []  # 田忌马匹速度
    qw = []  # 齐王马匹速度
    reward = 0
    for i in range(0, n):
        tj.append(random.randint(0, 100))
        qw.append(random.randint(0, 100))
    # 从小到大排序
    tj = sorted(tj)
    qw = sorted(qw)
    print(tj)
    print(qw)
    while len(tj):
        if tj[0] > qw[0]:  # 田忌最慢的马比齐王最慢的马快
            reward += 1
            del tj[0], qw[0]
        elif tj[0] == qw[0]:  # 田忌最慢马和齐王最慢的马一样
            del tj[0], qw[0]
        else:  # 田忌最慢的马比齐王最慢的马垃圾
            reward -= 1
            del tj[0], qw[-1]  # 删除田忌最慢的马和齐王最快的马
    print(reward)




def candy_demand():
    """
    题目:已知一些孩子和一些糖果,每个孩子有需求因子g,
    每个糖果有大小s,当某个糖果的大小s>=某个孩子的需求因子g时,
    代表该糖果可以满足该孩子,求使用这些糖果,最多能满足多少孩子
    (注意,某个孩子最多只能用1个糖果满足)
    :return:
    """
    g = [5, 10, 2, 9, 15, 9]
    s = [6, 1, 20, 3, 8]
    g = sorted(g)
    s = sorted(s)
    print(g)
    print(s)
    child = 0
    candy = 0
    while child < len(g) and candy < len(s):
        if g[child] <= s[candy]:
            child += 1
        candy += 1
    print(child)




def get_max_len():
    """
    给定一个整数序列,返回作为摆动序列的最长子序列的长度。
    通过从原始序列中删除一些(也可以不删除)元素来获得子序列,
    剩下的元素保持其原始顺序。
    :return:
    """
    arr = [1, 17, 5, 10, 13, 15, 10, 5, 16, 8]
    arr = [1,2,3,4,5,6,7,8,9]
    arr = [1,7,4,9,2,5]
    if len(arr) < 2:
        print(len(arr))
    else:


        # Begin = 0, Up = 1, Down = 2
        state = 0
        max_len = 1
        for i in range(1, len(arr)):
            if state == 0:
                if arr[i - 1] < arr[i]:
                    state = 1
                    max_len += 1
                elif arr[i - 1] > arr[i]:
                    state = 2
                    max_len += 1
            elif state == 1:
                if arr[i - 1] > arr[i]:
                    state = 2
                    max_len += 1


            elif state == 2:
                if arr[i - 1] < arr[i]:
                    state = 1
                    max_len += 1
        print(max_len)




def remove_digits():
    """
    题目:已知一个使用字符串表示非负整数num,将num中的k个数字移除,
    求移除k个数字后,可以获得的最小的可能的新数字
    (num不会以0开头,num长度小于10002)


例如:输入:num = “1432219”,k=3 
在去掉3个数字后得到的很多可能里,
如1432,4322,2219,1219;
去掉数字4、3、2、得到的1219最小


    :return:
    """
    a = "1430219"
    k = 2
    stack = []
    for num in a:
        number = int(num)
        while stack and k and int(stack[-1]) > number:
            stack.pop()
            k -= 1
        stack.append(num)
    while k and stack:
        stack.pop()
        k -= 1
    print(stack)
    if not stack:
        print("0")
    else:
        print("".join(stack))




def marry_candy_value():
    """
    4.圣诞节发糖果
    圣诞节来临了,在城市A中,圣诞老人准备分发糖果。
    现在有多箱不同的糖果,
每一种糖果都有自己的价值和重量。每箱糖果都可以拆分成任意散装组合带走。
圣诞老人的驯鹿最多只能承受一定重量的糖果。
请问圣诞老人最多能带走多大价值的糖果。


输入数据:


    输入的第一行由两个部分组成,分别为糖果箱数正整数n(1<=n<=100),
驯鹿能承受的最大重量正整数w(0<w<10000);其余n行每行对应一箱糖果,
由两部分正整数v和w组成,分别为一箱糖果的价值和重量。


输出要求:


    输出圣诞老人能带走的糖果的最大总价值,保留一位小数,输出为一行。


输出样例:


  4     15


  100  4


  412  8


  266  7


  591  2


输出样例:


  1193.0
    :return:
    """
    a = 4  # 箱数
    max_load = 15  # 麋鹿最大的载重量
    value = [100, 412, 266, 591]  # 每种糖果的总价值
    load = [4, 8, 7, 2]  # 每种糖果的总量
    value_per_load = []  # 单位重量价值
    list_load_state = []
    for i in range(len(value)):
        avg = round(value[i]/load[i], 1)  # 单位重量的价格
        value_per_load.append(avg)
        list_load_state.append([load[i], avg, False])  # [每种糖果对应的总重量, 单位重量的价格, 是否被取走]


    value_per_load.sort(reverse=True)  # 从大到小排序
    all_sum = [0, 0]  # 取走的总重量, 取走前的重量备份
    sum_value = 0  # 总价值
    flag = 0  # 是否超过马车总载重
    for i in range(len(value_per_load)):
        for j in range(len(list_load_state)):
            if flag == 0:  # 重量未超过,标志为0
                if value_per_load[i] == list_load_state[j][1] and (not list_load_state[j][2]):
                    all_sum[1] = all_sum[0]  # 备份取走前的总量
                    all_sum[0] += list_load_state[j][0]
                    current_get_load = list_load_state[j][0]
                    if all_sum[0] > max_load:  # 大于总载重,循环迭代减少单位重量
                        flag = 1  # 超出马车最大承重梁, flag=1


                        while True:
                            z = all_sum[1] + current_get_load  # 使用备份重量判断是否超过max_load
                            if z <= max_load:
                                break
                            current_get_load -= 1


                        all_sum[0] = all_sum[1]  # 回复原始的备份载重量
                        all_sum[0] += current_get_load  # 真实拿走的重量
                    sum_value += value_per_load[i] * current_get_load
                    list_load_state[j][2] = True  # 取走标志
            else:
                break
    print('Value:', sum_value)




def greedy():
    """
    一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。
    设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。
     对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。
    :return:
    """
    n = 100
    k = 5
    d = [50, 80, 39, 60, 40, 32]
    # 表示加油站之间的距离
    num = 0
    # 表示加油次数
    for i in range(k):
        if d[i] > n:
            print('no solution')
            # 如果距离中得到任何一个数值大于n 则无法计算
            return


    i, s = 0, 0
    # 利用s进行迭代
    while i <= k:
        s += d[i]
        if s >= n:
            # 当局部和大于n时, 则局部和更新为当前距离,表示加完油之后已经行驶的距离
            s = d[i]
            # 贪心意在令每一次加满油之后跑尽可能多的距离
            num += 1
        i += 1
    print(num)




if __name__ == '__main__':
    candy_demand()
    get_max_len()
    remove_digits()
    marry_candy_value()
    greedy()












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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值