Estructura de datos y algoritmo (2): clasificación (recursividad, retroceso, teoría de números, inserción, colina, fusión, selección, burbujeo, clasificación rápida, voraz, programación dinámica)

Clasificación de algoritmos: recursividad, retroceso, teoría de números, inserción, colina, fusión, selección, burbujeo, clasificación rápida, voraz, programación dinámica

Pensamiento de teoría de números: usar fórmulas matemáticas o teoremas o leyes para resolver problemas;

El punto más difícil en el pensamiento algorítmico: recursividad + programación dinámica; teoría del árbol: árbol binario, árbol rojo-negro

Preguntas para pensar:

  1. Hay un reembolso en el sistema de distribución de WeChat. Todos deben saber que, por ejemplo, B es A sin conexión y C es B sin conexión. Entonces A puede compartir el dinero de B y C durante el reembolso. En este momento, ¿simplemente Encontrar la última superior de B y C respectivamente. ¿Cómo solemos resolver este problema?

  2. Secuencia de Fibonacci: 1 1 2 3 5 8 13 21 ¿Cuáles son las características? Comenzar desde el tercer número es igual a la suma de los dos números anteriores; fórmula de solución: f(n)=f(n-1)+f(n-2) condición de terminación: n<=2 f(n)=1

recursión

definición recursiva

Por ejemplo, hay demasiada gente haciendo cola en una ventana determinada y no sé dónde estoy, así que le pregunto a la persona que está delante de mí quién está en la fila, porque sé dónde estoy cuando sé quién está. en
línea Pero las personas que están al frente no saben dónde se ubican, entonces, ¿qué deben hacer? También puede seguir preguntando hasta que se pregunte a la primera persona, y luego, de la primera persona a mí, sabré exactamente qué número soy. El escenario anterior es una recursividad típica. ¿Encontraste una regla en este proceso?Entonces habrá un proceso de preguntar, y habrá un proceso de regresar después de preguntar lo primero. Esto es pasar (pedir) más regresar (retorno). Entonces, ¿podemos usar una fórmula matemática para resolver este proceso? Entonces, ¿qué es esta fórmula matemática?

f(n)=f(n-1)+1

f(n): indica mi posición

f(n-1): significa la persona frente a mí;

llamate a ti mismo

Escenarios de aplicaciones recursivas

  1. 一个问题的解可以分解为几个子问题的解: Subproblema, podemos descomponer un problema de datos a gran escala en muchos problemas pequeños a través de la idea de divide y vencerás.
    Podemos considerar a la persona que acaba de hacer la pregunta como una subpregunta. Grande a pequeño

  2. Este problema y los subproblemas después de la descomposición,求解思路完全一样

  3. 一定有一个最后确定的答案,即递归的终止条件: La pregunta de ahora era la primera persona. La primera persona debe saber dónde está clasificado, es decir, cuando n=1, si no existe tal característica, entonces nuestra recursividad tendrá un ciclo infinito, y finalmente el programa desbordará la pila;

Análisis de la complejidad temporal y espacial de la recursividad

Tome la sucesión de Fibonacci como ejemplo para analizar el árbol recursivo: f(n)=f(n-1)+f(n-2)

Tanto la complejidad del tiempo como la del espacio: O(2^n)=>O(n) o O(nlogn)

optimización recursiva

inserte la descripción de la imagen aquí

  1. Usar no recursivo: todo el código recursivo teóricamente se puede convertir a no recursivo
  2. Únase al caché: guarde los resultados de nuestras operaciones intermedias, para que la recursión se pueda reducir a o (n)
  3. Recurrencia de cola: ¿qué es la recursión de cola? La recursión de cola significa que la función de llamada debe aparecer al final, sin ninguna otra operación. Porque cuando nuestro compilador compila el código, si encuentra que no hay ninguna operación al final de la función, no creará una nueva pila en este momento y la sobrescribirá al frente. Contando hacia atrás, no hay necesidad de retroceder, porque reduciremos los resultados intermedios cada vez.
// 斐波纳契/微信分销系统
// 1 1 2 3 5 8 13
// f(n) = f(n-1) + f(n-2)
// 递归
// 递归优化
// 1. 使用非递归
// 2. 加入缓存
// 3. 尾递归
// 递归注意事项----栈溢出和时间问题
public class FibonacciSeq {
    
    

    //递归 40 : 102334155 耗时:316 ms
    public static int fab(int n) {
    
     // 时间复杂度/空间复杂度 O(2^n) => 如何优化
        if (n <= 2) return 1;
        return fab(n - 1) + fab(n - 2);
    }

    //尾递 第一个优化 40 : 102334155 耗时:0 ms
    public static int noFab(int n) {
    
     // 不使用递归-节约空间
        if (n <= 2) return 1;
        int a = 1;
        int b = 1;
        int c = 0;
        for (int i = 3; i <= n; i ++) {
    
    
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }

    //尾递 40 : 102334155 耗时:0 ms
    public static int noFabSimple(int data[], int n) {
    
     // 不使用递归--占用空间
        if (n <= 2) return 1;
        data[1] = 1;
        data[2] = 1;
        for (int i = 3; i <= n; i ++) {
    
    
            data[i] = data[i - 1] + data[i - 2];
        }
        return data[n];
    }

    //尾递 40 : 102334155 耗时:0 ms
    public static int fab2(int data[], int n) {
    
    
        if (n <= 2) return 1;
        if (data[n] > 0) return data[n];

        int res = fab2(data,n-1) + fab2(data,n-2);
        data[n] = res;
        return res;
    }

    //尾递: 改成尾递归 prepre 上上一次运行结果  pre 上次运行结果
    public static int tailFab2(int n, int prepre, int pre) {
    
    
        if (n <= 2) return pre;
        return tailFab2(n - 1, pre, pre + prepre);
    }

    //求N的阶乘 用普通的递归怎么写 5=5*4*3*2*1 => f(n) = n * f(n-1)
    public static int fac(int n) {
    
    
        if (n <= 1) return 1;
        return n * fac(n - 1);
    }

    //改成尾递归 求N的阶乘 用普通的递归怎么写 5=5*4*3*2*1 => f(n) = n * f(n-1)
    public static int tailFac(int n, int res) {
    
    //尾递归
        if (n <= 1) return res;
        return tailFac(n-1, n * res);
    }


    public static void main(String[] args) {
    
    
//        for (int i = 1; i <= 40; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + fab(i) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//        for (int i = 1; i <= 40; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + noFab(i) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//        data = new int[41];
//        for (int i = 1; i <= 40; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + noFabSimple(data, i) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//        data = new int[41];
//        for (int i = 1; i <= 40; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + fab2(data, i) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//        for (int i = 1; i <= 40; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + tailFab2(i, 1, 1) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//
//        for (int i = 1; i <= 10; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + tailFac(i, 1) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
//
//        for (int i = 1; i <= 10; i++) {
    
    
//            long start = System.currentTimeMillis();
//            System.out.println(i + " : " + fac(i) + " 耗时:" + (System.currentTimeMillis() - start) + " ms");
//        }
    }
}
/**
 递归
 1 : 1 耗时:0 ms
 2 : 1 耗时:0 ms
 3 : 2 耗时:0 ms
 4 : 3 耗时:0 ms
 5 : 5 耗时:0 ms
 6 : 8 耗时:0 ms
 7 : 13 耗时:0 ms
 8 : 21 耗时:0 ms
 9 : 34 耗时:0 ms
 10 : 55 耗时:0 ms
 11 : 89 耗时:0 ms
 12 : 144 耗时:0 ms
 13 : 233 耗时:0 ms
 14 : 377 耗时:0 ms
 15 : 610 耗时:0 ms
 16 : 987 耗时:1 ms
 17 : 1597 耗时:0 ms
 18 : 2584 耗时:0 ms
 19 : 4181 耗时:0 ms
 20 : 6765 耗时:0 ms
 21 : 10946 耗时:0 ms
 22 : 17711 耗时:0 ms
 23 : 28657 耗时:1 ms
 24 : 46368 耗时:0 ms
 25 : 75025 耗时:0 ms
 26 : 121393 耗时:1 ms
 27 : 196418 耗时:1 ms
 28 : 317811 耗时:1 ms
 29 : 514229 耗时:1 ms
 30 : 832040 耗时:4 ms
 31 : 1346269 耗时:4 ms
 32 : 2178309 耗时:7 ms
 33 : 3524578 耗时:11 ms
 34 : 5702887 耗时:17 ms
 35 : 9227465 耗时:30 ms
 36 : 14930352 耗时:50 ms
 37 : 24157817 耗时:90 ms
 38 : 39088169 耗时:145 ms
 39 : 63245986 耗时:242 ms
 40 : 102334155 耗时:316 ms

不使用递归
 0 : 1 耗时:0 ms
 1 : 1 耗时:0 ms
 2 : 1 耗时:0 ms
 3 : 2 耗时:0 ms
 4 : 3 耗时:0 ms
 5 : 5 耗时:0 ms
 6 : 8 耗时:0 ms
 7 : 13 耗时:0 ms
 8 : 21 耗时:0 ms
 9 : 34 耗时:0 ms
 10 : 55 耗时:0 ms
 11 : 89 耗时:0 ms
 12 : 144 耗时:0 ms
 13 : 233 耗时:0 ms
 14 : 377 耗时:0 ms
 15 : 610 耗时:0 ms
 16 : 987 耗时:0 ms
 17 : 1597 耗时:0 ms
 18 : 2584 耗时:0 ms
 19 : 4181 耗时:0 ms
 20 : 6765 耗时:0 ms
 21 : 10946 耗时:0 ms
 22 : 17711 耗时:0 ms
 23 : 28657 耗时:0 ms
 24 : 46368 耗时:0 ms
 25 : 75025 耗时:0 ms
 26 : 121393 耗时:0 ms
 27 : 196418 耗时:0 ms
 28 : 317811 耗时:0 ms
 29 : 514229 耗时:0 ms
 30 : 832040 耗时:0 ms
 31 : 1346269 耗时:0 ms
 32 : 2178309 耗时:0 ms
 33 : 3524578 耗时:0 ms
 34 : 5702887 耗时:0 ms
 35 : 9227465 耗时:0 ms
 36 : 14930352 耗时:0 ms
 37 : 24157817 耗时:0 ms
 38 : 39088169 耗时:0 ms
 39 : 63245986 耗时:0 ms
 40 : 102334155 耗时:0 ms
 */

Ordenar análisis de rendimiento

  1. Eficiencia de tiempo: determina cuánto tiempo se ejecuta el algoritmo, O(1)
  2. complejidad del espacio
  3. Comparaciones e intercambios
  4. Estabilidad Después de ordenar 1 9 *3 5 3 第一种:1 *3 3 5 9 第二种:1 3 *3 5 9los mismos dos números, la posición relativa permanece sin cambios. ¿Cuál es el punto de una especie estable? ¿Dónde está la aplicación? Por ejemplo, clasificación de pedidos de comercio electrónico (de pequeño a grande, con la misma cantidad según el tiempo del pedido)

tipo de inserción

inserte la descripción de la imagen aquí

Mire el siguiente ejemplo: Clasificación por inserción en 7 8
9 0 4 3 9




 public static int[] insertSort(int arr[]) {
    
    
     for (int i = 1; i < arr.length; i++) {
    
    
         int curr = arr[i];
         int pre = i - 1;
         for (; pre >= 0 ; pre--) {
    
    
             if (curr < arr[pre]) {
    
    
                 arr[pre+1] = arr[pre];
             } else {
    
    
                 break;
             }
         }
         arr[pre+1] = curr;
     }
     return arr;
 }

clasificación de colinas

Segmentación incremental: sumar=n/2 n=10 =>5,2,1

   public static void shellSort(int data[]) {
    
    
       int n = data.length;

       for (int add = n/2; add >= 1 ; add/=2) {
    
    
           for (int i = add; i < n; i++) {
    
    
               int temp = data[i];
               int j = i - add;
               for (; j >= 0; j-=add) {
    
    
                   if (data[j] > temp) {
    
    
                       data[j + add] = data[j];
                   } else {
    
    
                       break;
                   }
               }
               data[j+add] = temp;
           }
       }
   }

ordenar por fusión

inserte la descripción de la imagen aquí


    public static void mergeSort(int[] arr, int left, int right) {
    
    
        if (left < right) {
    
    
            int mid = (left + right)/2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid+1, right);
            merge(arr, left, mid, right);
        }
    }

    public static void merge(int[] arr, int left, int mid, int right) {
    
    
        int temp[] = new int[arr.length];

        int leftPoint = left;
        int rightPoint = mid + 1;

        int cur = left; //当前位置

        while (leftPoint <= mid && rightPoint <= right) {
    
    
            if (arr[leftPoint] < arr[rightPoint]) {
    
    
                 temp[cur] = arr[leftPoint];
                 leftPoint++;
            } else {
    
    
                temp[cur] = arr[rightPoint];
                rightPoint++;
            }
            cur++;
        }

        while (leftPoint <= mid) {
    
    
            temp[cur++] = arr[leftPoint++];
        }

        while (rightPoint <= right) {
    
    
            temp[cur++] = arr[rightPoint++];
        }

        for (int i = left; i <= right; i++) {
    
    
            arr[i] = temp[i];
        }
    }

elegir

La idea de la clasificación por selección es muy similar a la clasificación por inserción, y también se divide en intervalos ordenados y no ordenados. Pero la ordenación por selección encontrará el elemento más pequeño del intervalo sin ordenar cada vez y lo colocará al final del intervalo ordenado. Pero a diferencia de la ordenación por inserción, la matriz se moverá, la ordenación por selección se intercambiará cada vez

    public static int[] selectSort(int data[]) {
    
    
        for (int i = 0; i < data.length -1; i++) {
    
    
            int minloc = i;
            for (int j = i+1; j < data.length; j++) {
    
    
                if (data[j] < data[minloc]) {
    
    
                    minloc = j;
                }
            }
            int minTemp = data[minloc];
            data[minloc] = data[i];
            data[i] = minTemp;
        }
        return data;
    }

burbuja

Idea central: la clasificación de burbujas solo funcionará en dos datos adyacentes. Cada operación de burbujeo comparará dos elementos adyacentes para ver si cumplen con los requisitos de relación de tamaño. Si no, cambia los dos. Un burbujeo moverá al menos un elemento a donde debería estar y se repetirá n veces para completar la clasificación de n datos.

El resultado del primer burbujeo: 4 5 6 3 2 1 -> 4 5 3 6 2 1 -> 4 5 3 2 6 1 -> 4 5 3 2 1 6, la posición de qué elemento se determina, 6 para el segundo
tiempo El resultado del burbujeo: 4 5 3 2 1 6 -> 4 3 5 2 1 6 -> 4 3 2 5 1 6 -> 4 3 2 1 5 6 El resultado del tercer burbujeo: 4 3 2 1 5
6- >3 4 2 1 5 6 -> 3 2 4 1 5 6 -> 3 2 1 4 5 6 El resultado de la
cuarta burbuja: 3 2 1 4 5 6 -> 2 3 1 4 5 6 -> 2 1 3 4 5 6
El resultado del quinto burbujeo: 2 1 3 4 5 6 -> 1 2 3 4 5 6

    public static int[] dubbleSort(int data[]) {
    
    
        for (int i = 0; i < data.length; i++) {
    
    
            for (int j = i+1; j < data.length; j++) {
    
    
                if (data[j] < data[i]) {
    
    
                    int temp = data[j];
                    data[j] = data[i];
                    data[i] = temp;
                }
            }
        }
        return data;
    }
    public static void dubbleSortTest(int arr[]) {
    
    
        for (int i = 0; i < arr.length-1; i++) {
    
    
            boolean flag = false;
            for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
                if (arr[j] > arr[j+1]) {
    
    
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = true;
                }
            }
            if (!flag) break;
        }
    }

fila rápida

inserte la descripción de la imagen aquí
Comparación de clasificación rápida y combinación:

  1. El procesamiento de la ordenación por fusión es de abajo hacia arriba, primero se procesan los subproblemas y luego se fusionan.
  2. La clasificación rápida es en realidad de arriba a abajo, la partición primero y luego se ocupa de los subproblemas sin fusionarlos.
    La optimización consiste en optimizar el número de referencia y dar una idea de tomar el medio de los tres números.

45 28 80 90 50 16 100 10
Número de referencia: Generalmente, es el primero de la secuencia que se ordena.
El primer número de referencia de clasificación: 45
Encuentre el número más pequeño que el número de referencia de atrás hacia adelante e intercambie:
*10 28 80 90 50 16 100 *45
Encuentre el número más grande que el número de referencia de adelante hacia atrás e intercambie :
10 28 * 45 90 50 16 100 *80
. . .
Divídalo en 3 partes por el número de referencia, la proporción de la izquierda es menor y la proporción de la derecha es mayor:
{10 28 16} 45 {50 90 100 80}
Esta es la primera vez que completa la clasificación con un Número de referencia de 45 dígitos.


    public static void quickSort(int data[], int left, int right) {
    
    
        int base = data[left]; //基准数

        int ll = left; //从左边找的位置
        int rr = right; //从右边找的位置

        while (ll < rr) {
    
    
            //从右边找比基数小的数
            while (ll < rr && data[rr] >= base) {
    
    
                rr--;
            }
            if (ll < rr) {
    
     //表示有找到比之大的
                 int temp = data[rr];
                 data[rr] = data[ll];
                 data[ll] = temp;
                 ll++;
            }

            while (ll < rr && data[ll] <= base) {
    
    
                ll++;
            }
            if (ll < rr) {
    
    
                int temp = data[rr];
                data[rr] = data[ll];
                data[ll] = temp;
                rr--;
            }

        }

        if (left < ll)
            quickSort(data, left, ll-1);

        if (ll < right)
            quickSort(data, ll+1, right);
    }

Comparado

inserte la descripción de la imagen aquí

Algoritmo codicioso

concepto

Concepto: El algoritmo codicioso también se llama algoritmo codicioso.Cuando resuelve un problema determinado, siempre obtiene el beneficio más inmediato.
Es decir, solo se preocupa por el presente e ignora la situación general, por lo que es una solución óptima local. Punto central: Deducir el óptimo global a través del óptimo local

La rutina del algoritmo codicioso: debe haber un género. Codificación de Huffman, algoritmo codicioso, algoritmo de compresión. camino más corto

preguntas de pensamiento

1. Una mañana, el líder de la empresa te pidió que resolvieras un problema. Mañana, la empresa tiene N reuniones del mismo nivel que necesitan usar la misma sala de reuniones. Ahora te dan la hora de inicio y finalización de las N reuniones. ¿Cómo se organiza la sala de reuniones
?¿Máxima utilización? Es decir, ¿la mayoría de las sesiones programadas? Para las películas, debe tener la mayor cantidad de boletos y la tasa de admisión más alta. Algoritmo Integral

2. Double Eleven llegará pronto, la diosa en la mente de Xiao C agregó N artículos al carrito de compras, y de repente ganó un premio para vaciar el carrito de compras con 5,000 yuanes de artículos (sin cambio), cada artículo solo si puede comprar uno, ¿cómo debería elegir el artículo para maximizar la cantidad ganadora? Si hay múltiples combinaciones óptimas, solo necesitas dar una. Oye, ahora la diosa te pregunta, ¿qué debes hacer?

/**
 * 贪心算法
 * 最优
 * 最短
 * 最好
 *
 * 先按照开始时间排序, 之后按照当前开始时间,比较开始时间是否大于结束时间
 */
public class Meeting implements Comparable<Meeting> {
    
    

    int meNum;
    int startTime;
    int endTime;

    public Meeting(int meNum, int startTime, int endTime) {
    
    
        super();
        this.meNum = meNum;
        this.startTime = startTime;
        this.endTime = endTime;
    }

    @Override
    public int compareTo(Meeting o) {
    
    
        if (this.endTime > o.endTime) {
    
    
            return 1;
        }
        return -1;
    }

    @Override
    public String toString() {
    
    
        return "GreedySort{" +
                "meNum=" + meNum +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                '}';
    }

    /**
     * 4
     * 0 9
     * 8 10
     * 10 12
     * 8 20
     * GreedySort{meNum=1, startTime=0, endTime=9}
     * GreedySort{meNum=3, startTime=10, endTime=12}
     */
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        List<Meeting> meetings = new ArrayList<>();
        int n = scanner.nextInt(); //会议
        for (int i = 0; i < n; i++) {
    
    
            int start = scanner.nextInt();
            int end = scanner.nextInt();
            Meeting meeting = new Meeting(i+1, start, end);
            meetings.add(meeting);
        }
        meetings.sort(null);

        int curTime = 0; //当前时间,从一天的0点开始
        for (int i = 0; i < n; i++) {
    
    
            Meeting meeting = meetings.get(i);
            if (meeting.startTime >= curTime) {
    
    
                System.out.println(meeting.toString());
                curTime = meeting.endTime;
            }
        }
    }
}

programación dinámica

Problema de pregunta-mochila para pensar: Un ladrón fue a una tienda a robar una mochila con una capacidad de 50 kg. Ahora tiene los siguientes artículos (el artículo no se puede dividir, y solo hay un artículo). ¿Cómo debe llevarla el ladrón a obtener el valor máximo?

cosa peso valor
Artículo 1 10kg 60 dolares
artículo 2 20kg 100 yuanes
Artículo 3 40kg 120 yuanes

inserte la descripción de la imagen aquí

bolsa de 5 kg

cosa peso valor
Artículo 1 1 6
artículo 2 2 10
Artículo 3 4 12

Divida la bolsa de 5 kg en 1 kg, calcule así, la tabla de adentro indica la mayor cantidad de dinero que se puede cargar con el peso actual. Las columnas de números en la tabla representan los elementos que se cargarán

cosa 1 kg 2kg 3 kg 4kg 5kg
añadir artículo 1 6 6 6 6 6
añadir elemento 2 6 10 10+6=16 10+6=16 dieciséis
añadir artículo 3 6 10 dieciséis dieciséis 18
/**
 * 背包算法
 * 购物车问题保存价值一样就可以
 */
public class Backpack {
    
    

    public static List<Integer> group(int dp[][], int good_list[]) {
    
    
        int value_max = dp[0].length - 1;
        int good_max = dp.length - 1;
        List<Integer> good_group = new ArrayList();
        while (value_max > 0 && good_max > 0) {
    
    
            if (dp[good_max][value_max] <= dp[good_max-1][value_max]) {
    
    
                good_max -= 1;
            } else {
    
    
                good_group.add(good_max);
                value_max -= good_list[good_max-1];
                good_max -= 1;
            }
        }
        return good_group;
    }

    public static int cart(int weight[], int lw) {
    
    
        int n = weight.length;
        int dp[][] = new int[n+1][lw+1]; //n表示物品、w表示重量,初始化全是0

        for (int i = 1; i <= n; i++) {
    
     //每次加的物品
            for (int w = 1; w <= lw; w++) {
    
    
                if (weight[i-1] <= w) {
    
     //当前物品重量小于分割重量 表示这个物品可以装进去
                    dp[i][w] = Math.max(weight[i-1] + dp[i-1][w-weight[i-1]], dp[i-1][w]);
                } else {
    
    
                    dp[i][w] = dp[i-1][w];
                }
            }
        }

        List<Integer> good_group = group(dp, weight);
        System.out.print("组合:");
        for (Integer integer : good_group) {
    
    
            System.out.print(integer + "\t");
        }
        System.out.println();

        return dp[n][lw];
    }

    public static int backpack(int value[], int weight[], int lw) {
    
    
        int n = weight.length;
        int dp[][] = new int[n+1][lw+1]; //n表示物品、w表示重量,初始化全是0

        for (int i = 1; i <= n; i++) {
    
     //每次加的物品
            for (int w = 1; w <= lw; w++) {
    
    
                if (weight[i-1] <= w) {
    
     //当前物品重量小于分割重量 表示这个物品可以装进去
                    dp[i][w] = Math.max(value[i-1] + dp[i-1][w-weight[i-1]], dp[i-1][w]);
                } else {
    
    
                    dp[i][w] = dp[i-1][w];
                }
            }
        }

        List<Integer> good_group = group(dp, weight);
        System.out.print("组合:");
        for (Integer integer : good_group) {
    
    
            System.out.print(integer + "\t");
        }
        System.out.println();

        return dp[n][lw];
    }

    /**
     * 组合:4	3	1
     * 8
     * 组合:3	1
     * 180
     */
    public static void main(String[] args) {
    
    
        System.out.println(cart(new int[]{
    
    1,2,3,4,5,9},8));

        System.out.println(backpack(new int[]{
    
    60, 100, 120},new int[]{
    
    10, 20, 30},40));
    }
}

Supongo que te gusta

Origin blog.csdn.net/menxu_work/article/details/130318770
Recomendado
Clasificación