Algorithme glouton (algorithme glouton)

idée principale

Lors de la résolution du problème, chaque étape sélectionne la solution optimale locale , dans l'espoir d'obtenir enfin la solution optimale globale.
(Le résultat final de l'algorithme glouton n'est pas nécessairement la solution optimale globale, mais c'est bien la solution optimale approximative .)


Problème classique Problème de couverture 1-set

Il y a n ensembles et chaque ensemble contient plusieurs éléments. Pour en trouver m ensembles, il est nécessaire de contenir tous les éléments des n ensembles et m est le plus petit.
Solutions générales:
(1) Liste toutes les combinaisons de n ensembles, car chaque ensemble peut être dans l'ensemble ou non dans l'ensemble, donc il y a un total de 2 n 2 ^ n2n types de schémas de combinaison.
(2) Dans ces schémas de combinaison, trouvez la combinaison de l'ensemble contenant tous les éléments, et la combinaison contient le plus petit nombre d'ensembles.

La complexité temporelle de cette méthode est O (2 n) O (2 ^ n)O ( 2n ), à mesure que n augmente, le temps augmente fortement et devient indisponible.

Idées d'algorithme gourmand (algorithme approximatif):
(1) Sélectionnez un ensemble qui contient les éléments les moins contenus.
(2) Répétez la première étape jusqu'à ce que l'ensemble sélectionné contienne tous les éléments.

La complexité temporelle de l'algorithme glouton est O (n 2) O (n ^ 2)O ( n2 ).
Exemple:
Il existe plusieurs ensembles comme suit, résolvez
set1 = {1, 2, 3};
set2 = {1, 3, 4};
set3 = {2, 5, 6};
set4 = {2, 3} ;
set5 = {6, 7};

Code:

public class GreedyAlgorithm {
    
    
    public Set<Integer> greedy(List<Set<Integer>> setList) {
    
    
    	//收集所有集合中的所有元素
        Set<Integer> needed = new HashSet<>();
        for (Set<Integer> set : setList) {
    
    
            for (int i : set) {
    
    
                needed.add(i);
            }
        }
        Set<Integer> result = new HashSet<>();
        while (!needed.isEmpty()) {
    
    
            int bestSet = 0;
            int bestCoveredSize = 0;
            for (int i = 0; i < setList.size(); i++) {
    
    
            	if (result.contains(i)) {
    
    
                    continue;
                }
                int coveredSize = 0;
                for (int j : setList.get(i)) {
    
    
                    if (needed.contains(j)) {
    
    
                        coveredSize++;
                    }
                }
                //体现出贪心算法,每次都选含有最多未包含元素的集合
                if (coveredSize > bestCoveredSize) {
    
    
                    bestSet = i;
                    bestCoveredSize = coveredSize;
                }
            }
            result.add(bestSet);
            needed.removeAll(setList.get(bestSet));

        }
        return result;
    }

    public static void main(String[] args) {
    
    
        List<Set<Integer>> setList = new ArrayList<>();
        setList.add(new HashSet<>(Arrays.asList(1, 2, 3)));
        setList.add(new HashSet<>(Arrays.asList(1, 3, 4)));
        setList.add(new HashSet<>(Arrays.asList(2, 5, 6)));
        setList.add(new HashSet<>(Arrays.asList(2, 3)));
        setList.add(new HashSet<>(Arrays.asList(6, 7)));
        System.out.println(new GreedyAlgorithm().greedy(setList));
    }
}

Problème classique Problème de vendeur itinérant

Il y a un agent de voyages qui a besoin de voyager de la ville A vers les autres villes n. Veuillez planifier son itinéraire pour que le trajet total soit le plus court.

Solution générale:
calculez n! N!n ! Parcourez les itinéraires et sélectionnez parmi eux l'itinéraire le plus court. La complexité temporelle estO (n!) O (n!)O ( n ! )

Idée d'algorithme gourmand:
chaque fois que vous choisissez la prochaine ville où vous voulez aller, choisissez la ville la plus proche où vous n'êtes pas allé.

Code

public class GreedyAlgorithm2 {
    
    
    public static int[] greedyAlgorithm2(int[][] distance, int n) {
    
    
        int[] result = new int[n];
        Set<Integer> notBeenTo = new HashSet<>(n);
        for (int i = 1; i <= n; i++) {
    
    
            notBeenTo.add(i);
        }

        int from = 0;
        for (int i = 0; i < result.length; i++) {
    
    
            int next = 0;
            for (int j : notBeenTo) {
    
    
                //体现出贪心算法,每次都选还没去过的距离最近的城市
                if (next == 0 || distance[from][next] > distance[from][j]) {
    
    
                    next = j;
                }
            }
            result[i] = next;
            from = next;
            notBeenTo.remove(next);
        }

        return result;
    }

    //测试代码
    public static void main(String[] args) {
    
    
        int n = 4;
        int[][] distance = new int[n + 1][n + 1];
        //0表示旅行商当前所在城市A, 1...n表示要去的城市
        Random rnd = new Random();
        for (int i = 0; i < distance.length; i++) {
    
    
            for (int j = 0; j < i; j++) {
    
    
                if (i != j) {
    
    
                    distance[i][j] = distance[j][i] = rnd.nextInt(10) + 1;
                }
            }
        }
        for (int[] arr : distance) {
    
    
            System.out.println(Arrays.toString(arr));
        }
        System.out.println();
        int[] result = greedyAlgorithm2(distance, n);
        System.out.println(Arrays.toString(result));
    }
}

Problème complet NP

En ce qui concerne le problème P, le problème NP, le problème NP complet (NPC), le problème NP-difficile (NPH), veuillez Baidu par vous-même, mais je n'ai pas trouvé de réponse satisfaisante (je ne l'ai pas comprise).

  • La définition simple des problèmes NP-complets est connue sous le nom de problèmes difficiles à résoudre (problèmes qui ne peuvent pas être résolus en temps polynomial), tels que le problème de couverture d'ensemble et le problème du voyageur de commerce.
  • Pour juger qu'un problème est NP-complet, il n'est pas nécessaire de trouver une solution parfaite, mais d'utiliser un algorithme approximatif. Mais il est difficile de juger si un problème est NP-complet, car la différence entre les problèmes faciles à résoudre et les problèmes NP-complets est généralement très faible. Tels que "le problème du chemin le plus court entre deux points" et "le problème du voyageur de commerce".

La méthode suivante peut être utilisée pour simplement (pas nécessairement) juger si le problème est NP-complet.

  • Lorsque le nombre d'éléments est petit, l'algorithme fonctionne très vite, mais à mesure que le nombre d'éléments augmente, la vitesse devient très lente.
  • Les problèmes impliquant «toutes les combinaisons» sont généralement NP-complets.
  • Le problème ne peut pas être divisé en petits problèmes, toutes les situations possibles doivent être considérées. Cela peut être un problème NP-complet.
  • Si le problème implique une séquence (telle que la séquence de la ville dans le problème du voyageur de commerce) et est difficile à résoudre, il peut s'agir d'un problème NP-complet.
  • Si le problème concerne une collection (comme une collection de stations de diffusion) et est difficile à résoudre, il peut s'agir d'un problème NP-complet.
  • Si le problème peut être transformé en problème de couverture d'ensemble ou en problème de voyageur, il doit être NP-complet.

Référence: "Diagramme d'algorithmes" Chapitre 8 Algorithme glouton

Je suppose que tu aimes

Origine blog.csdn.net/AmorFati1996/article/details/110998879
conseillé
Classement