欲張りアルゴリズムに関する記事

創造を続け、成長を加速させましょう!「ナゲッツデイリーニュープラン・6月アップデートチャレンジ」に参加して2日目です。クリックしてイベントの詳細をご覧ください。

前書き

人間は最初は本質的に善良ですが、自分の経験や生活環境などの影響を受けて、次第に貪欲、憎しみ、妄想を育んでいきます。実際、人々は貪欲であるだけでなく、私たちのアルゴリズムも貪欲になります。今日は、アルゴリズムがどのように貪欲を生成するかを確認するために、貪欲を使用した次のアルゴリズムモデルである貪欲アルゴリズムを紹介します。

欲張りアルゴリズムとは

問題を分析して解決する場合、各ステップの計算の選択肢が最適または最良であり、このようにして、最終的な計算結果が最適であることが期待されます。つまり、アルゴリズムは最初に局所的な最適解を探すことによって、全体的な最適解を探します。

欲張りアルゴリズムの基本的な手順:

1.最初に問題を定義し、問題モデルが欲張りアルゴリズムの使用、つまり最大値問題の解決に適しているかどうかを判断します。

2.極値を見つける問題を分解し、分解後に各サブ問題を解き、現在のサブ問題の局所最適解を得ようとします。

3.すべてのサブ問題の局所最適解が解決された後、これらの局所最適解が集約およびマージされて、最終的なグローバル最適解が得られます。この最適解は、問題全体の最適解です。

image.png

シーン理解アルゴリズムを介して

概念的なアルゴリズムの説明は、すべての人によく理解されているとは限らないため、実際のシナリオと組み合わせて説明する必要があります。ここでは、子供時代の変化を見つけて切り込む例を取り上げます。今では誰もが携帯電話でスキャンして支払いをしていますが、お金に触れてから久しぶりですが、欲張りアルゴリズムの実装プロセスを理解するのに役立つ変更の問題を妨げることはありません。

あなたが小さな小売店のオーナーであり、1元、3元、5元などのさまざまな額面で変更があったとします。この時、子供が何かを買いに来て、ポケットに収まるように少しでも変化を見つけてほしいと頼まれました。変化をc[0]、c [1]、c [2] ...として記録し、子供たちがおやつを購入するために使用するお金を合計として記録するとします。次に、子供が最小限の変更を取得したいということを述べました。これをプログラミングの問題に変換して、最適なソリューションを見つけることができます。つまり、総数が与えられると、ソリューションには最小数のcの合計が必要になります。与えられた合計に等しくなります。

例1:

検出される変更が11であり、現在の変更が1、3、および5であるとします。

入力:total = 11、c [0] = 1、c [1] = 3、c [2] = 5

出力:3

問題分析

通过提取问题中的关键词“最少”,我们可以明确此问题的实际上就是一个求解最值的问题,只要找到满足条件的最小零钱张数就可以解决找回最少零钱的问题了。想要找到最小的零钱张数,我们最先想到的方法就是进行穷举,列举出来所有可能的满足总数为11的零钱组合。如下图所示,再在这些组合中找到使用零钱张数最少的组合再计算具体的张数,我们就可以获得最终的答案了。但是这显然不是一个好的解决思路。因为如果对应的total很大,我们穷举的结果将会爆发性增长。

image.png

那有没有更好的解决办法呢?这时候我们就可以考虑下贪心算法的实现了,找到满足要求的最小张数零钱。既然是找零钱,那么我们可以将问题转换为找到满足总数total的零钱最少需要几个步骤,实际上就是将问题拆分到每次找零钱的小步骤中,而贪心算法的核心就是需要在每个小步骤中贪心寻求局部最优解。因此在找零钱的每个步骤中,都需要找到该步骤中对应的最优解零钱大小,接下来我们来一起看下贪心算法执行过程。这里假设各个面值的零钱比较充足。

在寻找零钱的步骤中,首先获取最大面值为5的零钱(贪心,上来就找最大的),接着发现剩余待找零钱6=11-5,于是继续寻找最大的面值为5的零钱(继续贪心),待找零钱1=6-5。此时只要获取面值为1的零钱就可以完成任务了,再将之前步骤中的结果整合到一起,最终我们得出想要获取total为11的最少张数零钱的大小为3。通过这样的分析,贪心算法是不是也没有那么的复杂。

image.png

对应的代码实现如下所示:

 
/**
 * @Author: mufeng
 * @Date: 2022/5/15 15:33
 * @Version: V 1.0.0
 * @Description: 计算最小满足条件的零钱张数
 */
public class MinChangeCountSolution {
 
    public static void main(String[] args) {
        int values[] = {5,5,3,3,1};
        System.out.println(getMinChangeCount(11, values));
 
    }
 
    //假设values数组从大到小排列
    static int getMinChangeCount(int total, int[] values) {
        int rest = total;
        int result = 0;
        int count = values.length;
 
        // 从大到小遍历所有面值
        for (int i = 0; i < count; ++ i) {
            //计算需要几张这种面值的零钱
            int needCount = rest / values[i];
            //计算使用后的余额
            rest -= needCount * values[i];
            //计数增加
            result += needCount;
 
            if (rest == 0) {
                return result;
            }
        }
        //没有找到合适的面值
        return -1;
    }
 
}
复制代码

以上我们分析了贪心算法的大致实现过程,但是实际上还是有问题的。不知道大家有没有发现,由于贪心算法过于贪心,每一个步骤都想要找到局部最优解。那么假如在上面的例子中,我们没有1块钱的零钱,上述代码的返回结果是-1,即没有符合条件的答案。但是实际并非如此,也就是说5,3,3也是满足条件的,但是上述代码却没有找到。

したがって、上記のコードにはまだ問題があります。重要な点は、1元の変更がないことがわかった場合は、戻って、2番目のステップで5元の変更を3元の変更に変更できるかどうかを確認する必要があるということです。その後、後続の反復を実行します。このような手順を実行すると、5、3、3などの組み合わせを見つけることができます。

image.png

まとめこの記事では、主に、欲張りアルゴリズムの説明と実際のお金の変更の例を組み合わせて、欲張りアルゴリズムの特定の実装プロセスを分析します。同時に、欲張りアルゴリズムの欠点を分析します。つまり、局所的な最適性の罠に陥りやすく、それ自体を脱出することができないため、条件を満たす最終結果を得ることができません。


作成は簡単ではありません。記事が悪くないと思われる場合は、+お気に入り+コメントを付けて交換してください。いつものように、記事の終わりに、私はあなたと詩を共有します。

Ding Fengbo・南シナ海の王DingguoのアテンダントYuNiangへの帰還

チャンは世界の卓ユランを羨ましく思います。神々はケーキを頼んで注文する必要があります。チンゲは白い歯を通り過ぎましたが、風が強くなり、雪が舞い、炎の海が涼しくなりました。

何千マイルも離れたところから戻ってくると、顔はどんどん少なくなり、笑顔はまだ嶺美の香りに包まれています。彼はリンナンが良いかどうか尋ねました、しかし彼は言いました:この心の安らぎの場所は私の故郷です。

おすすめ

転載: juejin.im/post/7102976328516763679