3
votes

Algorithme des sommes lentes

Supposons que nous ayons une liste de N nombres et répétions l'opération suivante jusqu'à ce qu'il ne nous reste plus qu'un seul nombre: choisissez deux nombres consécutifs quelconques et remplacez-les par leur somme. De plus, nous associons à chaque opération une pénalité égale à la valeur du nouveau nombre et appelons la pénalité pour toute la liste comme la somme des pénalités de chaque opération.

Remarque: les nombres consécutifs signifient que leurs index dans le tableau sont consécutifs, pas que leurs valeurs sont consécutives. Par exemple, étant donné la liste [1, 2, 3, 4, 5], nous pourrions choisir 2 et 3 pour la première opération, ce qui transformerait la liste en [1, 5, 4, 5] et encourrait une pénalité de 5 Le but de ce problème est de trouver la pire pénalité possible pour une entrée donnée.

Contraintes: 1 â ‰ ¤ N â ‰ ¤ 10 ^ 6 1 â ‰ ¤ Ai â ‰ ¤ 10 ^ 7, où * Ai désigne le ième élément initial d'un tableau. La somme des valeurs de N sur tous les cas de test ne dépassera pas 5 * 10 ^ 6.

int getTotalTime(int[] arr) {}
Example
arr = [4, 2, 1, 3]
output = 23
First, add 4 + 2 for a penalty of 6. Now the array is [6, 1, 3]
Add 6 + 1 for a penalty of 7. Now the array is [7, 3]
Add 7 + 3 for a penalty of 10. The penalties sum to 23.


2 commentaires

Pourriez-vous publier tout le contenu de votre question? Les liens externes peuvent mourir et votre question serait incomplète.


Vous recherchez l'algorithme le plus rapide? Ou quel est votre objectif?


4 Réponses :


0
votes

Je l'ai résolu comme ça mais je ne sais pas si c'est optimal ou non

static int getTotalTime(int[] arr) {
        List<Integer> output = new ArrayList<>();
        Arrays.stream(arr).forEach(output::add);
        if (output.size() < 3) {
            return output.stream().reduce((a, b) -> a + b).get();
        }

        int sum = 0;
        List<Integer> max1 = new ArrayList<>();
        max1.add(0);
        for (int i = 2; i < output.size(); i++) {
            if (output.get(i) + output.get(i - 1) > output.get(max1.get(0)) + output.get(max1.get(0) + 1)) {
                max1 = new ArrayList<>();
                max1.add(i - 1);
            }else if (output.get(i) + output.get(i - 1) == output.get(max1.get(0)) + output.get(max1.get(0) + 1)) {
                max1.add(i - 1);
            }
        }

        sum = sum + output.get(max1.get(0)) + output.get(max1.get(0) + 1);

        List newList = new ArrayList(output);
        newList.set(max1.get(0), output.get(max1.get(0)) + output.get(max1.get(0) + 1));
        newList.remove(max1.get(0) + 1);

        int remainingSum = getTotalTime(newList);

        for (int i = 1; i < max1.size(); i++) {
            newList = new ArrayList(output);
            newList.set(max1.get(i), output.get(max1.get(i)) + output.get(max1.get(i) + 1));
            newList.remove(max1.get(i) + 1);
            int nextRemainingSum = getTotalTime(newList);
            if (nextRemainingSum > remainingSum) {
                remainingSum = nextRemainingSum;
            }
        }

        sum += remainingSum;

        return sum;
    }

    static int getTotalTime(List<Integer> output) {
        int sum = 0;
        while (output.size() > 2) {
            int max1 = 0;
            for (int i = 2; i < output.size(); i++) {
                if (output.get(i) + output.get(i - 1) > output.get(max1) + output.get(max1 + 1)) {
                    max1 = i - 1;
                }
            }
            sum += output.get(max1) + output.get(max1 + 1);
            output.set(max1, output.get(max1) + output.get(max1 + 1));
            output.remove(max1 + 1);
        }

        return sum + output.stream().reduce((a, b) -> a + b).get();

    }


1 commentaires

Lorsque vous vous interrogez sur l'algorithme, vous pouvez expliquer en quoi consiste l'algorithme que vous implémentez dans ce programme. Inutile de saisir trop de détails.



0
votes

C'est un problème gourmand. La clé derrière cela est de remarquer que nous devons toujours suivre la plus grande somme possible à chaque itération. Dans votre cas [4, 2, 1, 3] , la première plus grande somme est 6 , puis 7 puis 10 .

Le problème survient lorsque la plus grande somme apparaît plusieurs fois, par exemple [5, 3, 7, 1] , alors vous devez choisir s'il vaut mieux commencer par [5, 3] ou [7, 1] .

#include <bits/stdc++.h>
using namespace std;

int n = 6;                       //array size
int a[] = {2, 1, 7, 1, 5, 3};    //array

vector<pair<int, int>> v;        //positions we will analyse

void analyse(){                  //this method gets the positions with biggest sum
    int sum = 0;
    for(int i = 1; i < n; i++) sum = max(sum, a[i - 1] + a[i]);
    for(int i = 1; i < n; i++) if(a[i - 1] + a[i] == sum) v.push_back(make_pair(i - 1, i));
}

int evaluate_penalty(int i, int j){   //given a position, this method finds
    int l = i, r = j;                 //the biggest penalty starting there
    int penalty = a[i] + a[j];
    int val = penalty;
    while(i != 0 || j != n - 1){
        if(l > 0 && r < n - 1) {
            if(a[l - 1] > a[r + 1]) l--;
            else r++;
        }
        else if(l > 0) l--;
        else r++;

        val += (l != i ? a[l] : 0) + (r != j ? a[r] : 0);
        penalty += val;
        i = l; j = r;
    }
    return penalty;
}

int max_penalty(){            //this method finds the biggest penalty
    v.clear();                //within all the possible starting positions.
    analyse();
    int maxPenalty = 0;
    for(int i = 0; i < v.size(); i++){
        maxPenalty = max(maxPenalty, evaluate_penalty(v[i].first, v[i].second));
    }
    return maxPenalty;
}

int main(){
    cout<<max_penalty()<<endl;
    return 0;
}

La complexité est O (n²) , MAIS dans la plupart des cas, ce sera O (n) . Étant donné que la plus grande somme entre deux nombres consécutifs est s , la complexité dépend du nombre de paires de nombres consécutifs somme s . S'il n'y en a qu'un (comme dans votre exemple [4, 2, 1, 3] , il se terminera en une itération, d'où O (n). Si le tableau est quelque chose comme [1, 1, 1, 1, 1, ..., 1] , il faudra O (n²).


1 commentaires

Ouais, ça ressemble presque à ma solution. Je ne sais pas s'il y a une meilleure approche ou non, mais au moins cela confirme la mienne. Merci



0
votes

Voici une solution optimisée en Javascript comprenant quelques cas de test. Le principe clé est que la pénalité la plus élevée peut être obtenue à chaque étape en ajoutant les deux plus grands éléments du tableau.

//Begin Solution
function getTotalTime(arr) {
    function getTotal(a){
      if(a.length==2)
        return a[0]+a[1]
      else{
        const penalty = a[a.length-1]+a[a.length-2]
        return penalty+getTotal([...a.slice(0,a.length-2),penalty])
      }
          
    }
  return getTotal(arr.slice(0,arr.length).sort((a,b)=>a-b))
}
 //End Solution

  // These are the tests we use to determine if the solution is correct.

  function printInteger(n) {
    var out = '[' + n + ']';
    return out;
  }
  
  var test_case_number = 1;
  
  function check(expected, output) {
    var result = (expected == output);
    var rightTick = "\u2713";
    var wrongTick = "\u2717";
    if (result) {
      var out = rightTick + ' Test #' + test_case_number;
      console.log(out);
    }
    else {
      var out = '';
      out += wrongTick + ' Test #' + test_case_number + ': Expected ';
      out += printInteger(expected);
      out += ' Your output: ';
      out += printInteger(output);
      console.log(out);
    }
    test_case_number++;
  }
  
  var arr_1 = [4, 2, 1, 3];
  var expected_1 = 26;
  var output_1 = getTotalTime(arr_1);
  check(expected_1, output_1);
  
  var arr_2 = [2, 3, 9, 8, 4];
  var expected_2 = 88;
  var output_2 = getTotalTime(arr_2);
  check(expected_2, output_2);

  


0 commentaires

0
votes

Il existe une solution meilleure et simple à ce problème en utilisant MaxHeap.

int getTotalPenalty (int[] arr) {
    PriorityQueue<Integer> q = new PriorityQueue<>(Collections.reverseOrder());
    for(int i = 0; i < arr.length; i++) {
        q.add(arr[i]);
    }
    int totalP = 0;
    while(q.size() > 1) {
        int penality =  q.poll() + q.poll();
        totalP = totalP + penality;
        q.add(penality);
    }
    return totalP;
}


0 commentaires