Structure des données et algorithme (2) : tri (récursivité, backtracking, théorie des nombres, insertion, Hill, fusion, sélection, bouillonnement, tri rapide, glouton, programmation dynamique)

Tri par algorithme : récursivité, backtracking, théorie des nombres, insertion, Hill, fusion, sélection, bouillonnement, tri rapide, glouton, programmation dynamique

Réflexion sur la théorie des nombres : utiliser des formules mathématiques, des théorèmes ou des lois pour résoudre des problèmes ;

Le point le plus difficile de la pensée algorithmique : récursivité + programmation dynamique ; théorie des arbres : arbre binaire, arbre rouge-noir

Questions de réflexion :

  1. Il y a une remise dans le système de distribution WeChat. Tout le monde doit savoir que, par exemple, B est hors ligne pour A et C est hors ligne pour B. A peut alors partager l'argent de B et C pendant la remise. Pour trouver le dernier supérieur de B et C respectivement. Comment résolvons-nous habituellement ce problème ?

  2. Suite de Fibonacci : 1 1 2 3 5 8 13 21 Quelles sont les caractéristiques ? Partir du troisième nombre est égal à l'addition des deux nombres précédents ; formule de solution : f(n)=f(n-1)+f(n-2) condition de terminaison : n<=2 f(n)=1

récursivité

définition récursive

Par exemple, il y a trop de gens qui font la queue à une certaine fenêtre, et je ne sais pas où je suis, alors je demande à la personne devant moi qui fait la queue, parce que je sais où je suis quand je sais qui est en ligne
. Mais les gens devant ne savent pas où ils se classent, alors que doivent-ils faire ? Il peut aussi continuer à demander jusqu'à ce qu'on demande à la première personne, puis de la première personne à moi, je saurai exactement quel numéro je suis. Le scénario ci-dessus est une récursivité typique. Avez-vous trouvé une règle dans ce processus ? Ensuite, il y aura un processus de demande, et il y aura un processus de retour après avoir demandé la première. C'est passe (demander) plus retour (retour). Pouvons-nous utiliser une formule mathématique pour résoudre ce processus ? Quelle est donc cette formule mathématique ?

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

f(n) : indique ma position

f(n-1) : désigne la personne devant moi ;

appelez-vous

Scénarios d'application récursive

  1. 一个问题的解可以分解为几个子问题的解: Sous-problème, nous pouvons décomposer un problème de données à grande échelle en plusieurs petits problèmes grâce à l'idée de diviser pour mieux régner.
    On peut considérer la personne qui a posé la question tout à l'heure comme une sous-question. Grand à petit

  2. Ce problème et les sous-problèmes après décomposition,求解思路完全一样

  3. 一定有一个最后确定的答案,即递归的终止条件: La question tout à l'heure était la première personne. La première personne doit savoir où elle est classée, c'est-à-dire quand n = 1, s'il n'y a pas une telle fonctionnalité, alors notre récursivité aura une boucle infinie, et finalement le programme débordera de la pile ; pile hors de

Analyse de la complexité temporelle et spatiale de la récursivité

Prenons la suite de Fibonacci comme exemple pour analyser l'arbre récursif : f(n)=f(n-1)+f(n-2)

Complexité temporelle et complexité spatiale : O(2^n)=>O(n) ou O(nlogn)

optimisation récursive

insérez la description de l'image ici

  1. Utiliser non récursif : tout code récursif peut théoriquement être converti en code non récursif
  2. Rejoindre le cache : enregistrer les résultats de nos opérations intermédiaires, afin que la récursivité puisse être réduite à o(n)
  3. Récursivité de la queue : qu'est-ce que la récursivité de la queue ? La récursivité de queue signifie que la fonction appelante doit apparaître à la fin, sans aucune autre opération. Parce que lorsque notre compilateur compile le code, s'il constate qu'il n'y a pas d'opération à la fin de la fonction, il ne créera pas de nouvelle pile à ce moment et ne l'écrasera pas au premier plan. En comptant à rebours, il n'est pas nécessaire de revenir en arrière, car nous ferons tomber les résultats intermédiaires à chaque fois.
// 斐波纳契/微信分销系统
// 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
 */

Analyse des performances de tri

  1. Efficacité temporelle : détermine la durée d'exécution de l'algorithme, O(1)
  2. complexité de l'espace
  3. Comparatifs & Echanges
  4. Stabilité Une fois 1 9 *3 5 3 第一种:1 *3 3 5 9 第二种:1 3 *3 5 9les deux mêmes nombres triés, la position relative reste inchangée. Quel est l'intérêt d'un tri stable ? Où est la candidature ? Par exemple, le tri des commandes e-commerce (du plus petit au plus gros, avec le même montant selon l'heure de la commande)

tri par insertion

insérez la description de l'image ici

Regardez l' exemple suivant : Tri par insertion sur 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;
 }

Tri de colline

Segmentation incrémentale : add=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;
           }
       }
   }

tri par fusion

insérez la description de l'image ici


    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];
        }
    }

choisir

L'idée du tri par sélection est très similaire au tri par insertion, et elle est également divisée en intervalles triés et non triés. Mais le tri par sélection trouvera à chaque fois le plus petit élément de l'intervalle non trié et le placera à la fin de l'intervalle trié. Mais contrairement au tri par insertion, le tableau sera déplacé, le tri par sélection sera échangé à chaque fois

    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;
    }

bulle

Idée centrale : le tri à bulles ne fonctionnera que sur deux données adjacentes. Chaque opération de bouillonnement comparera deux éléments adjacents pour voir s'ils répondent aux exigences de relation de taille. Sinon, échangez les deux. Un bouillonnement déplacera au moins un élément là où il devrait être, et répétera n fois pour terminer le tri de n données.

Le résultat du premier bouillonnement : 4 5 6 3 2 1 -> 4 5 3 6 2 1 -> 4 5 3 2 6 1 -> 4 5 3 2 1 6, dont la position est déterminée, 6 pour le second
temps Le résultat du bouillonnement : 4 5 3 2 1 6 -> 4 3 5 2 1 6 -> 4 3 2 5 1 6 -> 4 3 2 1 5 6 Le résultat du troisième bouillonnement : 4 3 2 1 5
6- >3 4 2 1 5 6 -> 3 2 4 1 5 6 -> 3 2 1 4 5 6 Le résultat de la
quatrième bulle : 3 2 1 4 5 6 -> 2 3 1 4 5 6 -> 2 1 3 4 5 6
Le résultat du cinquième bouillonnement : 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;
        }
    }

rangée rapide

insérez la description de l'image ici
Comparaison du tri rapide et de la fusion :

  1. Le traitement du tri par fusion est ascendant, traitant d'abord les sous-problèmes, puis fusionnant.
  2. Le tri rapide est en fait de haut en bas, partitionner d'abord, puis traiter les sous-problèmes sans les fusionner.
    L'optimisation consiste à optimiser le nombre de référence et à donner une idée de prise au milieu des trois nombres.

45 28 80 90 50 16 100 10
Numéro de repère : Généralement, c'est le premier de la séquence à trier.
Le premier numéro de référence de tri : 45
Trouver le nombre plus petit que le numéro de référence de l'arrière vers l'avant et échanger :
*10 28 80 90 50 16 100 *45
Trouver le nombre plus grand que le numéro de référence de l'avant vers l'arrière et échanger :
10 28 * 45 90 50 16 100 *80
. . .
Divisez-le en 3 parties par le numéro de référence, le rapport à gauche est plus petit, et le rapport à droite est plus grand :
{10 28 16} 45 {50 90 100 80}
C'est la première fois que vous complétez le tri avec un Numéro de référence à 45 chiffres.


    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);
    }

Par rapport

insérez la description de l'image ici

Algorithme gourmand

concept

Concept : L'algorithme glouton est aussi appelé algorithme glouton. Lorsqu'il résout un certain problème, il en tire toujours le bénéfice le plus immédiat.
C'est-à-dire qu'il ne se soucie que du présent et ignore la situation globale, c'est donc une solution optimale locale. Point central : Déduire l'optimum global par l'optimum local

La routine de l'algorithme glouton : il doit y avoir un tri. Codage de Huffman, algorithme glouton, algorithme de compression. le plus court chemin

questions de réflexion

1. Un matin, le dirigeant de l'entreprise vous demande de résoudre un problème. Demain, l'entreprise a N réunions de même niveau qui doivent utiliser la même salle de réunion. On vous donne maintenant l'heure de début et de fin des N réunions Comment aménagez-vous la salle de réunion
? Utilisation maximale ? C'est-à-dire, le plus de sessions programmées ? Pour les films, il doit avoir le plus de billets et le taux d'admission le plus élevé. Algorithme complet

2. Double Eleven arrive bientôt, la déesse dans l'esprit de Xiao C a ajouté N articles au panier, et tout à coup, elle a remporté un prix pour vider le panier avec 5 000 yuans d'articles (pas de changement), chaque article uniquement si elle peut acheter Premièrement, comment doit-elle choisir l'objet pour maximiser le montant du gain ? S'il existe plusieurs combinaisons optimales, vous n'avez qu'à en donner une. Hé, maintenant la déesse vous demande, que devez-vous faire ?

/**
 * 贪心算法
 * 最优
 * 最短
 * 最好
 *
 * 先按照开始时间排序, 之后按照当前开始时间,比较开始时间是否大于结束时间
 */
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;
            }
        }
    }
}

programmation dynamique

Question de réflexion sur le problème du sac à dos : un voleur s'est rendu dans un magasin pour voler un sac à dos d'une capacité de 50 kg. Il dispose maintenant des éléments suivants (l'élément ne peut pas être divisé et il n'y a qu'un seul élément). Comment le voleur doit-il le prendre pour obtenir la valeur maximale ?

chose lester valeur
Objet 1 10 kg 60 dollars
Point 2 20 kg 100 yuans
Point 3 40 kg 120 yuans

insérez la description de l'image ici

sac de 5 kg

chose lester valeur
Objet 1 1 6
Point 2 2 dix
Point 3 4 12

Divisez le sac de 5 kg en 1 kg, calculez comme ceci, le tableau à l'intérieur indique le plus d'argent pouvant être chargé sous le poids actuel. Les colonnes numériques du tableau représentent les éléments à charger

chose 1 kg 2 kg 3 kg 4kg 5kg
ajouter l'élément 1 6 6 6 6 6
ajouter l'élément 2 6 dix 10+6=16 10+6=16 16
ajouter l'élément 3 6 dix 16 16 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));
    }
}

Je suppose que tu aimes

Origine blog.csdn.net/menxu_work/article/details/130318770
conseillé
Classement