哆啦A梦带你了解贪心算法

贪心算法是一种基于贪心思想的算法设计方法,它通过每一步的最优选择来达到全局最优解。贪心算法的应用非常广泛,比如在图论、动态规划、网络流等领域都有着重要的应用。在接下来的博客中,我们将讲述贪心算法的基本思想、应用场景和实现方法,以及如何评估贪心算法的正确性和效率。

当我们在生活中做决策时,经常会采用贪心思想,即每一步都选择当前最优的方案,以期望最终达到全局最优解

接下来我们用可爱的哆啦A梦举例来初步了解贪心算法

 有一天,小哆啦去买铜锣烧,看到商店里的铜锣烧都被装在袋子里成袋的销售,每袋100元

但是哆啦A梦身上只有200元,只够买两袋铜锣烧,细心的小哆啦发现每个袋子里装的铜锣烧数量并不是相同的,有多有少,但是价格都是相同的每袋一百元,那么哆啦A梦怎么才能吃到最多的铜锣烧呢?

要想吃到最多的铜锣烧,就需要小哆啦从超市里这么多铜锣烧当中选出和最大的两袋,我们把问题简化一下,只需要选择出铜锣烧数量最多和第二多的两袋即可。

但是如果把所有袋子都排序再选择前两个的话会花费很多时间,我们来看看哆啦A梦是怎么做的

首先,哆啦A梦拿起了离自己最近的两袋铜锣烧,发现一个袋子里有10个,一个袋子里有15个,接着哆啦A梦又拿起了第三个袋子发现里面有12个。

小哆啦想了一下,第三个袋子并没有第二个袋子中的铜锣烧多,但是比第一个袋子多,所以哆啦A梦决定放弃第一个袋子,这样他就能吃到12+15=27个铜锣烧。

哆啦A梦拿起第四个袋子,发现有17个,比之前的袋子里都要多,由于所以哆啦A梦只需要拿到最多的两个袋子就可以了,所以他放弃了有12个铜锣烧的第三个袋子,拿起了第四个袋子,这样他可以吃到15+17=32个铜锣烧

以此类推,每拿起一个袋子都和自己手里的比较一下,如果比自己手里的其中一个数量多就替换掉,如果没有手里的多就继续往后看,每次都选择当前条件下最多的两个袋子,当哆啦A梦把所有的袋子都看过一遍之后,他手上拿的一定是最多的两袋铜锣烧,这便是贪心算法的核心思想:即每一步都选择当前最优的方案,并希望通过这种局部最优解来达到全局最优解

下面我们定义一个包含两个整型数的数组来表示哆啦A梦选择的两个袋子,用一个长一些的数组来表示超市的铜锣烧:

public class TLS {
    public  int[] doraemon=new int[2];//哆啦A梦选择的两个袋子
    public static int[] shop={10,15,12,17,6,46,33,11,23,7,8,6,4,10,23,43,20,34};
    //超市的铜锣烧


    public  int[] choose(int[] shop){
        int Max=0;//目前铜锣烧数量最多的袋子
        int secMax=0;//目前铜锣烧数量第二多的袋子
        for (int i : shop) {
            if (i > Max) {//如果比两个都多
                secMax = Max;
                Max = i;
            } else if (i > secMax) {//如果只比第二个多
                secMax = i;
            }
        }
        doraemon[0]=Max;
        doraemon[1]=secMax;
        return doraemon;
    }

    public static void main(String[] args) {
        
        System.out.println(Arrays.toString(new TLS().choose(shop)));
    }
}

我们定义了两个数组,doraemon表示小哆啦选择的铜锣烧,shop表示超市中的铜锣烧,在choose方法中我们每遍历到一个元素都进行一次比较

我们可以看到只需遍历一次就可以选出铜锣烧数量最多的两个袋子,这便是贪心算法的基本雏形 

再举个例子,哆啦A梦结账时发现超市打折,两袋铜锣烧只需要133元,需要找回67元,哆啦A梦想要拿最少的纸币或者硬币来拿回找回的67元,那么他会怎么做呢

按照小哆啦贪心的算法,只需要每次选择面额最大的纸币/硬币,凑够67元就是最优解,那么结果真的是这样吗?我们再写一个算法按照他的逻辑来实现一下:

public class Change {
    public static void main(String[] args) {
        int[] coins = {50, 20, 10, 5, 1}; // 纸币和硬币的面额
        int amount = 67; // 需要找回的钱数

        int[] result = new int[coins.length]; // 存储每种面额的纸币和硬币的数量
        int total = 0; // 找回的钱数

        for (int i = 0; i < coins.length; i++) {
            while (total + coins[i] <= amount) {
                result[i]++;
                total += coins[i];
            }
        }

        System.out.println("找零方案为:");
        for (int i = 0; i < coins.length; i++) {
            if (result[i] > 0) {
                System.out.println(coins[i] + "元面额的纸币或硬币:" + result[i] + "张");
            }
        }
    }
}

在这个算法中,我们假设每种硬币或纸币的数量不限,需要找回 67元的零钱。程序中使用了一个 result 数组来存储每种面额的纸币和硬币的数量,使用了一个 total 变量来记录已经找回的钱数。在每一次循环中,程序会选择当前最大面额的纸币或硬币,直到找回的钱数等于 67 元为止。最后,程序会输出找零的方案。

接下来我们运行一下:

我们可以看到,按照贪心算法的策略,找回 67 元的最优方案一共需要的纸币数为1+1+1+2=5张

需要注意的是,贪心算法并不一定能够得到全局最优解,因为每一步的选择都是基于当前的局部最优解,而不考虑未来的影响。因此,在应用贪心算法时,需要对算法的正确性进行评估,并且需要注意算法的局限性。

比如,当纸币和硬币的面额不是一组相互整除的数时,贪心算法就不一定能得到最优解。

例如,如果coins数组中的面额为{3, 5, 7},amount为8时,贪心算法会选择一张面额为7的纸币和一张面额为1的纸币,共计两张纸币。但是最优解应该是选择两张面额为3的纸币,共计两张纸币。

所以说贪心算法并不是万能的,对于一些问题,贪心算法可能无法得到最优解,此时需要考虑其他的算法。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值