Algoritmo codicioso + Programación dinámica|Diferentes perspectivas determinan diferentes profundidades

Este artículo está participando en el "Proyecto Golden Stone. Comparte 60,000 premios en efectivo"

prefacio

  • Cuando vaya a la universidad, habrá un curso llamado "Algoritmo y práctica", y se sentirá genial si el algoritmo se combina con C++él . En retrospectiva, los algoritmos no se limitan a los idiomas, pero la sintaxis de cada idioma es diferente, pero la lógica interna del algoritmo es la misma. Hoy usamos tres casos para comprender y analizar uno de los algoritmos [Algoritmo codicioso].

Introducción

  • Un algoritmo codicioso significa que siempre se puede lograr una solución óptima local. ¿Qué quieres decir? Es decir, se selecciona la solución óptima en cada paso de la escena, independientemente de que se pueda alcanzar la solución óptima global.
  • Los algoritmos codiciosos y la programación dinámica tienen muchas similitudes. El problema al que es aplicable el algoritmo voraz es también la subestructura óptima. Existe una diferencia significativa entre el algoritmo voraz y la programación dinámica, es decir, en el algoritmo voraz, la subestructura óptima se usa de arriba hacia abajo. El algoritmo codicioso primero hará una elección, que parece ser la opción óptima en ese momento, y luego resolverá un subproblema de resultado, en lugar de encontrar primero la solución óptima del subproblema y luego tomar una decisión.
  • A continuación, experimentemos la动态规划 diferencia entre , y , a través de diferentes escenarios. 贪心算法Para tener una comprensión más profunda de 贪心lo que es? Por qué la codicia solo se puede lograr 局部最优解.

Escenas

intercambio de cambio

Tema Descripción

 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
 ​
 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
 ​
 你可以认为每种硬币的数量是无限的。
复制代码
  • La traducción es: Supongamos que hay 1 yuan, 2 yuan, 5 yuan, 10 yuan, 20 yuan, 50 yuan y 100 yuan respectivamente c0, c1, c2, c3, c4, c5, c6. Ahora, para usar este dinero para pagar K yuanes, al menos cuánto cambio se debe cambiar.

ideas para resolver problemas

  • No es difícil encontrar la mejor solución a este problema 动态规划. Para una matriz dada que compone K elementos desde los elementos de la matriz. S(K-1)=1+min(S(ki)).

imagen-20221115211416720.png

Ejemplo 1: Supongamos

monedas = [1, 2, 5], cantidad = 11, entonces, cuando i==0i==0 no se puede componer con monedas, es 0. Cuando i<0i<0, ignora F(i)F(i)

F(i) 最小硬币数量 F(0) 0 //金额为0不能由硬币组成 F(1) 1 //F(1)=min(F(1-1),F(1-2),F(1-5))+1=1F(1)=min(F(1−1),F(1−2),F(1−5))+1=1 F(2) 1 //F(2)=min(F(2-1),F(2-2),F(2-5))+1=1F(2)=min(F(2−1),F(2−2),F(2−5))+1=1 F(3) 2 //F(3)=min(F(3-1),F(3-2),F(3-5))+1=2F(3)=min(F(3−1),F(3−2),F(3−5))+1=2 F(4) 2 //F(4)=min(F(4-1),F(4-2),F(4-5))+1=2F(4)=min(F(4−1),F(4−2),F(4−5))+1=2 ... ... F(11) 3 //F(11)=min(F(11-1),F(11-2),F(11-5))+1=3F(11)=min(F(11−1),F(11−2),F(11−5))+1=3 我们可以看到问题的答案是通过子问题的最优解得到的。

AC代码

 public class Solution {
     public int coinChange(int[] coins, int amount) {
         int max = amount + 1;
         int[] dp = new int[amount + 1];
         Arrays.fill(dp, max);
         dp[0] = 0;
         for (int i = 1; i <= amount; i++) {
             for (int j = 0; j < coins.length; j++) {
                 if (coins[j] <= i) {
                     dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                 }
             }
         }
         return dp[amount] > amount ? -1 : dp[amount];
     }
 }
复制代码

玩筹码

题目描述

 有 n 个筹码。第 i 个筹码的位置是 position[i] 。
 ​
 我们需要把所有筹码移到同一个位置。在一步中,我们可以将第 i 个筹码的位置从 position[i] 改变为:
 ​
 position[i] + 2 或 position[i] - 2 ,此时 cost = 0
 position[i] + 1 或 position[i] - 1 ,此时 cost = 1
 返回将所有筹码移动到同一位置上所需要的 最小代价 。
复制代码

imagen-20221115162933576.png

解题思路

  • 所谓算法其实也是前人总结出来的经验罢了。初看毫无头绪,再看仍无头绪这就是算法的魅力,当我们知道此题可以通过 贪心 来解决时就有了头绪了。

  • 首先通过题目描述我们能够得处一下结论:

    • 每次仅能移动一个筹码
    • 每次移动范围介于1~2之间
    • 移动2步长,无代价
    • 移动1步长,则付出1代价
  • 移动2步无需付出代价,意味着我们可以将筹码分成两组,组内成员所在位置索引差值皆为 2 。最终只需要考虑哪组需要合并即可。

image-20221115163927066.png

  • 因为移动两步时无需代价的,则按照上面分组后,组内合并则是无需付出代价的。合并后如下

image-20221115164121666.png

  • En este punto solo necesitamos Aconsiderar si el grupo se mueve al Bgrupo o el Bgrupo se mueve al Agrupo. La base para este juicio es ver cuál de los dos grupos tiene el número más pequeño. Porque también tenemos la limitación de que solo se puede mover una ficha a la vez. Entonces, un grupo con un número pequeño se muda a un grupo con un número grande. En otras palabras, el número de un grupo con un número pequeño es el costo total de la mudanza.

código de CA

 class Solution {
     public int minCostToMoveChips(int[] position) {
         int even = 0, odd = 0;
         for (int pos : position) {
             if ((pos & 1) != 0) {
                 odd++;
             } else {
                 even++;
             }
         }
         return Math.min(odd, even);
     }
 }
复制代码

extensión de actualización

  • Lo anterior ya puede satisfacer las necesidades. Pero como empresa en desarrollo durante tantos años, ya me he acostumbrado a las funciones de extensión reservadas. Después de unirnos, introducimos una nueva estrategia y movemos el costo de tres pasos. En este momento, podemos modificar el código como este
 ​
 public int minCostToMoveChips(int[] position) {
         int step = 2;
         int[] stepArr = new int[step];
         for (int pos : position) {
             int posIndex=pos%step;
             stepArr[posIndex]++;
         }
         int min = stepArr[0];
         for (int i = 1; i < stepArr.length; i++) {
             if (min > stepArr[i]) {
                 min = stepArr[i];
             }
         }
         return min;
     }
复制代码

image-20221115165216674.png

boxeo

Tema Descripción

 请你将一些箱子装在 一辆卡车 上。给你一个二维数组 boxTypes ,其中 boxTypes[i] = [numberOfBoxesi, numberOfUnitsPerBoxi] :
 ​
 numberOfBoxesi 是类型 i 的箱子的数量。
 numberOfUnitsPerBoxi 是类型 i 每个箱子可以装载的单元数量。
 整数 truckSize 表示卡车上可以装载 箱子 的 最大数量 。只要箱子数量不超过 truckSize ,你就可以选择任意箱子装到卡车上。
 ​
 返回卡车可以装载 单元 的 最大 总数。
 ​
复制代码

ideas para resolver problemas

  • 玩筹码Se puede decir que el juego se implementó inteligentemente usando greedy, tal vez no nos hayamos dado cuenta completamente del papel del algoritmo greedy. Y 装箱子es la idea de un minucioso algoritmo codicioso. 零钱兑换Lo que uso es 动态规划que se caracteriza por un proceso de abajo hacia arriba. Los resultados aguas arriba dependen de los resultados aguas abajo.
  • El 贪心算法medio es 自上而下, por ejemplo, en esta pregunta, asumimos que Fx representa la capacidad máxima después de que el auto se llene con X cajas. Obviamente solo tenemos que elegir la mayor capacidad entre las cajas restantes cada vez.
  • También se puede ver a partir de la estrategia de selección de los dos que el algoritmo codicioso es solo una solución óptima local. en lugar de la solución óptima global.

código de CA

 class Solution {
     public int maximumUnits(int[][] boxTypes, int truckSize) {
         Arrays.sort(boxTypes, (a, b) -> b[1] - a[1]);
         int res = 0;
         for (int[] boxType : boxTypes) {
             int numberOfBoxes = boxType[0];
             int numberOfUnitsPerBox = boxType[1];
             if (numberOfBoxes < truckSize) {
                 res += numberOfBoxes * numberOfUnitsPerBox;
                 truckSize -= numberOfBoxes;
             } else {
                 res += truckSize * numberOfUnitsPerBox;
                 break;
             }
         }
         return res;
     }
 }
复制代码

Resumir

1. No se puede garantizar que la solución final obtenida sea la mejor 2. No se puede utilizar para encontrar el valor máximo o mínimo 3. Solo se puede encontrar el rango de soluciones factibles que satisfacen ciertas restricciones

Este artículo está participando en el "Proyecto Golden Stone. Comparte 60,000 premios en efectivo"

Supongo que te gusta

Origin juejin.im/post/7166803488096124958
Recomendado
Clasificación