Στην πληροφορική, το **πρόβλημα μέγιστου αθροίσματος υποακολουθίας** (Αγγλικά: *maximum sum subarray problem*) είναι ένα πρόβλημα όπου έχουμε μια σειρά (πίνακα) από αριθμούς (θετικούς, αρνητικούς ή μηδενικούς) και ψάχνουμε τη συνεχή υποσειρά (υποπίνακα) αριθμών που δίνει το μεγαλύτερο άθροισμα. Για παράδειγμα, στη σειρά των αριθμών −2, 1, −3, 4, −1, 2, 1, −5, 4 η υποσειρά αριθμών με το μέγιστο άθροισμα είναι η 4, −1, 2, 1, με άθροισμα 6.

Εφαρμογές
---------

Το πρόβλημα μέγιστου αθροίσματος υποακολουθίας έχει πρακτικές εφαρμογές στη Βιοπληροφορική για την ανάλυση γονιδιακών αλληλουχιών και στην μηχανική όραση για την ανίχνευση των πιο φωτεινών σημείων σε μια ψηφιογραφική εικόνα.

Αλγόριθμος Kadane
-----------------

Σύμφωνα με τον αλγόριθμο του Kadane σαρώνουμε τις τιμές του πίνακα, και κάθε φορά υπολογίζουμε τη θέση με το μέγιστο θετικό άθροισμα της υποσειράς που τερματίζεται στο συγκεκριμένο σημείο. Η υποσειρά μπορεί να είναι άδεια (στην περίπτωση που το άθροισμα είναι μηδέν) ή να περιέχει περισσότερους από έναν αριθμούς από την προηγούμενη κατάσταση.  Στη γλώσσα Python η υλοποίηση του αλγορίθμου είναι:

```
def max\_subarray(A):
    max\_ending\_here = max\_so\_far = 0
    for x in A:
        max\_ending\_here = max(0, max\_ending\_here + x)
        max\_so\_far = max(max\_so\_far, max\_ending\_here)
    return max\_so\_far

```

Μια τροποποίηση του προβλήματος επιτρέπει την επιστροφή υποσειρών μηδενικού μεγέθους στις περιπτώσεις που ολόκληρος ο πίνακας περιέχει αρνητικούς αριθμούς και φαίνεται στο παρακάτω κώδικα:

```
def max\_subarray(A):
    max\_ending\_here = max\_so\_far = A[0]
    for x in A[1:]:
        max\_ending\_here = max(x, max\_ending\_here + x)
        max\_so\_far = max(max\_so\_far, max\_ending\_here)
    return max\_so\_far

```

Παρακάτω βρίσκεται η υλοποίηση σε C++ όπου μπορεί να επιστρέψει (βρίσκονται σχολιασμένα) και τους δείκτες αρχής και τέλος της υποσειράς:

```
int sequence(std::vector<int> const & numbers) {
 // Αρχικοποίηση μεταβλητών
 int max\_so\_far = numbers[0], max\_ending\_here = numbers[0];

 // ΠΡΟΑΙΡΕΤΙΚΟ: Αυτές οι μεταβλητές μπορούν να χρησιμοποιηθούν για να έχουμε τους δείκτες αρχής και τέλους της υποσειράς
 // size\_t begin = 0;
 // size\_t begin\_temp = 0;
 // size\_t end = 0;

 // Βρες την υποσειρά κάνοντας επανάληψη μέχρι το τέλος του πίνακα
 for(size\_t i = 1; i < numbers.size(); i++) {
 // υπολογισμός max\_ending\_here
 if(max\_ending\_here < 0) {
 max\_ending\_here = numbers[i];
 
 // begin\_temp = i;
 }
 else {
 max\_ending\_here += numbers[i];
 }

 // υπολογισμός max\_so\_far
 if(max\_ending\_here >= max\_so\_far ) {
 max\_so\_far = max\_ending\_here;
 
 // begin = begin\_temp;
 // end = i;
 }
 }
 return max\_so\_far ;
}

```

Ο αλγόριθμος μπορεί εύκολα να τροποποιηθεί και να αποθηκεύει τα σημεία της υποσειράς η οποία έχει μέγιστο άθροισμα (δείτε σχολιασμένο κώδικα). Η πολυπλοκότητα του αλγόριθμου Kadane είναι {\displaystyle {\mathcal {O}}(n)}.

Διαίρει και βασίλευε
--------------------

Ένας αλγόριθμος που επιλύει το πρόβλημα αυτό με χρήση της μεθόδου *Διαίρει και βασίλευε*, παρουσιάστηκε από τον Jon Bentley του 1984 με πολυπλοκότητα {\displaystyle {\mathcal {O}}(n\log n)}. 
Παρακάτω δίνεται ο κώδικας σε Python ώστε να ελέγχει εάν είναι κενός ο πίνακας ή αν όλοι οι αριθμοί είναι αρνητικοί και να επιστέφει τη μέγιστη τιμή καθώς και την αρχή και το τέλος του υποπίνακα.

```
def max\_subarray\_Onlogn(arr,begin=-1,last=-1):
    if begin==-1:
        #αν δεν έχει δοθεί όριο βάζουμε όλο τον πίνακα
        begin=0
        last=len(arr)-1
    if begin>last:
        return (0,-1,0)
    elif begin==last:
        return [arr[begin],begin,begin]
    median= int((begin+last)/2)
    lmax=sumx=arr[median]
    start=median
    for i in range(median-1,begin-1,-1):
        sumx+=arr[i]
        if sumx>lmax:
            lmax=sumx
            start=i

    rmax=sumx=arr[median+1]
    end=median+1
    for i in range(median+2,last+1,+1):
        sumx+=arr[i]
        if sumx>rmax:
            rmax=sumx
            end=i
    k=max\_subarray\_Onlogn(arr,begin,median)
    if k[0]<lmax+rmax:
        k=(lmax+rmax,start,end)
    j=max\_subarray\_Onlogn(arr,median+1,last)
    if k[0]<j[0]or k[1]==-1:
        return j
    return k

```

Παραπομπές
----------

1. ↑   Brodal, Gerth Stølting; Jørgensen, Allan Grønlund (2007), «A linear time algorithm for the *k* maximal sums problem», *Mathematical Foundations of Computer Science 2007*, Lecture Notes in Computer Science, **4708**, Springer-Verlag, σελ. 442–453, doi:10.1007/978-3-540-74456-6\_40
2. ↑  Takaoka, T. (2002), «Efficient algorithms for the maximum subarray problem by distance matrix multiplication», *Electronic Notes in Theoretical Computer Science* **61**, ανακτήθηκε στις 2014-06-05
3. ↑  Κλεάνθους Λοίζου, Στέλλα. «1 ΕΠΛ 231 – Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο 03: Πίνακες / Συλλογές Μέγιστο Άθροισμα Υπο‐ακολουθίας» (PDF). *ΕΠΛ 231 : Δομές Δεδομένων και Αλγόριθμοι*. Τμήμα Πληροφορικής Πανεπιστήμιου Κύπρου. Αρχειοθετήθηκε από το πρωτότυπο (PDF) στις 20 Απριλίου 2015. Ανακτήθηκε στις 5 Ιουνίου 2014.
4. ↑   Bentley, Jon (1984), «Programming pearls: algorithm design techniques», *Communications of the ACM* **27** (9): 865–873, doi:10.1145/358234.381162