Partizionamento equo degli elementi di un elenco


12

Dato un elenco di valutazioni dei giocatori, mi viene richiesto di dividere i giocatori (cioè le valutazioni) in due gruppi nel modo più equo possibile. L'obiettivo è ridurre al minimo la differenza tra la valutazione cumulativa delle squadre. Non ci sono vincoli su come dividere i giocatori nelle squadre (una squadra può avere 2 giocatori e l'altra squadra può avere 10 giocatori).

Ad esempio: [5, 6, 2, 10, 2, 3, 4]dovrebbe tornare([6, 5, 3, 2], [10, 4, 2])

Mi piacerebbe conoscere l'algoritmo per risolvere questo problema. Si prega di notare che sto seguendo un corso introduttivo di programmazione online, quindi sarebbero apprezzati semplici algoritmi.

Sto usando il seguente codice, ma per qualche motivo, il correttore di codice online dice che non è corretto.

def partition(ratings):
    set1 = []
    set2 =[]
    sum_1 = 0
    sum_2 = 0
    for n in sorted(ratings, reverse=True):
        if sum_1 < sum_2:
            set1.append(n)
            sum_1 = sum_1 + n
        else:
            set2.append(n)
            sum_2 = sum_2 + n
    return(set1, set2)

Aggiornamento: ho contattato gli istruttori e mi è stato detto che avrei dovuto definire un'altra funzione di "aiuto" all'interno della funzione per controllare tutte le diverse combinazioni, quindi ho bisogno di verificare la differenza minima.


2
"Problema della somma dei sottoinsiemi" di Google
John Coleman,

@JohnColeman grazie per il tuo suggerimento. Potete per favore guidarmi nella giusta direzione su come usare somme di sottoinsieme per risolvere il mio problema?
EddieEC,

6
Ancora più specificamente, hai un caso speciale del problema della somma dei sottoinsiemi che si chiama problema della partizione . L'articolo di Wikipedia su di esso discute algoritmi.
John Coleman,

4
Questo risponde alla tua domanda? Dividi l'elenco in un algoritmo in due parti uguali
kaya3,

1
Grazie ad entrambi! Sinceramente apprezzo l'aiuto!
EddieEC,

Risposte:


4

Nota: modificato per gestire meglio il caso in cui la somma di tutti i numeri è dispari.

Il backtracking è una possibilità per questo problema.

Permette di esaminare tutte le possibilità in modo ricorsivo, senza la necessità di una grande quantità di memoria.

Si interrompe non appena viene trovata una soluzione ottimale:, sum = 0dove si sumtrova la differenza tra la somma degli elementi dell'insieme A e la somma degli elementi dell'insieme B. MODIFICA: si interrompe non appena sum < 2, per gestire il caso in cui la somma di tutti i numeri è dispari, ovvero corrisponde a una differenza minima di 1. Se questa somma globale è pari, la differenza minima non può essere uguale a 1.

Permette di implementare una semplice procedura di abbandono prematuro :
in un dato momento, se sumè maggiore della somma di tutti gli elementi rimanenti (cioè non collocati in A o B) più il valore assoluto del minimo corrente ottenuto, allora possiamo smettere di esaminare il percorso corrente, senza esaminare gli elementi rimanenti. Questa procedura è ottimizzata con:

  • ordina i dati di input in ordine decrescente
  • A ogni passaggio, esamina innanzitutto la scelta più probabile: questo consente di passare rapidamente a una soluzione quasi ottimale

Ecco uno pseudo-codice

Inizializzazione:

  • ordina gli elementi a[]
  • Calcola la somma degli elementi rimanenti: sum_back[i] = sum_back[i+1] + a[i];
  • Impostare la "differenza" min sul valore massimo: min_diff = sum_back[0];
  • Inserisci a[0]in A -> l'indice idell'elemento esaminato è impostato su 1
  • Set up_down = true;: questo valore booleano indica se stiamo andando avanti (vero) o indietro (falso)

Mentre loop:

  • If (up_down): avanti

    • Prova l'abbandono prematuro, con l'aiuto di sum_back
    • Seleziona il valore più probabile, regola in sumbase a questa scelta
    • if (i == n-1): LEAF -> verifica se il valore ottimale è migliorato e ritorna se il nuovo valore è uguale a 0 (EDIT:) if (... < 2); andare indietro
    • Se non in una foglia: continua ad andare avanti
  • Se (! Updown): indietro

    • Se arriviamo a i == 0 : ritorno
    • Se è la seconda passeggiata in questo nodo: selezionare il secondo valore, salire
    • altro: scendi
    • In entrambi i casi: ricalcolare il nuovo sumvalore

Ecco un codice, in C ++ (Scusa, non conosco Python)

#include    <iostream>
#include    <vector>
#include    <algorithm>
#include    <tuple>

std::tuple<int, std::vector<int>> partition(std::vector<int> &a) {
    int n = a.size();
    std::vector<int> parti (n, -1);     // current partition studies
    std::vector<int> parti_opt (n, 0);  // optimal partition
    std::vector<int> sum_back (n, 0);   // sum of remaining elements
    std::vector<int> n_poss (n, 0);     // number of possibilities already examined at position i

    sum_back[n-1] = a[n-1];
    for (int i = n-2; i >= 0; --i) {
        sum_back[i] = sum_back[i+1] + a[i];
    }

    std::sort(a.begin(), a.end(), std::greater<int>());
    parti[0] = 0;       // a[0] in A always !
    int sum = a[0];     // current sum

    int i = 1;          // index of the element being examined (we force a[0] to be in A !)
    int min_diff = sum_back[0];
    bool up_down = true;

    while (true) {          // UP
        if (up_down) {
            if (std::abs(sum) > sum_back[i] + min_diff) {  //premature abandon
                i--;
                up_down = false;
                continue;
            }
            n_poss[i] = 1;
            if (sum > 0) {
                sum -= a[i];
                parti[i] = 1;
            } else {
                sum += a[i];
                parti[i] = 0;
            }

            if (i == (n-1)) {           // leaf
                if (std::abs(sum) < min_diff) {
                    min_diff = std::abs(sum);
                    parti_opt = parti;
                    if (min_diff < 2) return std::make_tuple (min_diff, parti_opt);   // EDIT: if (... < 2) instead of (... == 0)
                }
                up_down = false;
                i--;
            } else {
                i++;        
            }

        } else {            // DOWN
            if (i == 0) break;
            if (n_poss[i] == 2) {
                if (parti[i]) sum += a[i];
                else sum -= a[i];
                //parti[i] = 0;
                i--;
            } else {
                n_poss[i] = 2;
                parti[i] = 1 - parti[i];
                if (parti[i]) sum -= 2*a[i];
                else sum += 2*a[i];
                i++;
                up_down = true;
            }
        }
    }
    return std::make_tuple (min_diff, parti_opt);
}

int main () {
    std::vector<int> a = {5, 6, 2, 10, 2, 3, 4, 13, 17, 38, 42};
    int diff;
    std::vector<int> parti;
    std::tie (diff, parti) = partition (a);

    std::cout << "Difference = " << diff << "\n";

    std::cout << "set A: ";
    for (int i = 0; i < a.size(); ++i) {
        if (parti[i] == 0) std::cout << a[i] << " ";
    }
    std::cout << "\n";

    std::cout << "set B: ";
    for (int i = 0; i < a.size(); ++i) {
        if (parti[i] == 1) std::cout << a[i] << " ";
    }
    std::cout << "\n";
}

L'unico problema qui non è sempre la somma ottimale sarà 0. Ti ringrazio per averlo spiegato abbastanza bene, perché non riesco a leggere bene C ++.
EddieEC,

Se la somma ottimale non è uguale a 0, il codice esamina tutte le possibilità, memorizzando la soluzione migliore. I percorsi non esaminati sono quelli di cui siamo sicuri che non siano ottimali. Questo corrisponde al ritorno if I == 0. L'ho provato sostituendo 10 con 11 nel tuo esempio
Damien

3

Penso che dovresti fare il prossimo esercizio da solo, altrimenti non impari molto. Per quanto riguarda questo, ecco una soluzione che cerca di attuare i consigli del tuo istruttore:

def partition(ratings):

    def split(lst, bits):
        ret = ([], [])
        for i, item in enumerate(lst):
            ret[(bits >> i) & 1].append(item)
        return ret

    target = sum(ratings) // 2
    best_distance = target
    best_split = ([], [])
    for bits in range(0, 1 << len(ratings)):
        parts = split(ratings, bits)
        distance = abs(sum(parts[0]) - target)
        if best_distance > distance:
            best_distance = distance
            best_split = parts
    return best_split

ratings = [5, 6, 2, 10, 2, 3, 4]
print(ratings)
print(partition(ratings))

Produzione:

[5, 6, 2, 10, 2, 3, 4]
([5, 2, 2, 3, 4], [6, 10])

Si noti che questo output è diverso da quello desiderato, ma entrambi sono corretti.

Questo algoritmo si basa sul fatto che, per selezionare tutti i possibili sottoinsiemi di un determinato set con N elementi, è possibile generare tutti gli interi con N bit e selezionare l'elemento I-esatto in base al valore dell'i-esimo bit. Vi lascio aggiungere un paio di righe per interrompere non appena lo best_distancezero (perché non può andare meglio, ovviamente).

Un po 'su bit (nota che 0bè il prefisso per un numero binario in Python):

Un numero binario: 0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57

Spostato a destra di 1: 0b0111001 >> 1 == 0b011100 == 28

Spostato a sinistra di 1: 0b0111001 << 1 == 0b01110010 == 114

Spostato a destra di 4: 0b0111001 >> 4 == 0b011 == 3

Bit a bit &(e):0b00110 & 0b10101 == 0b00100

Per verificare se il 5o bit (indice 4) è 1: (0b0111001 >> 4) & 1 == 0b011 & 1 == 1

Uno seguito da 7 zeri: 1 << 7 == 0b10000000

7 quelli: (1 << 7) - 1 == 0b10000000 - 1 == 0b1111111

Tutte le combinazioni di 3-bit: 0b000==0, 0b001==1, 0b010==2, 0b011==3, 0b100==4, 0b101==5, 0b110==6, 0b111==7(si noti che 0b111 + 1 == 0b1000 == 1 << 3)


Grazie mille! Puoi per favore spiegare cosa hai fatto? Inoltre a che serve <<? Queste cose, per esempio, non ho mai imparato a fare. Ma sapevo che dovevo generare tutte le possibilità e restituire quella con la minima differenza!
EddieEC,

Ho aggiunto un microlessone sui numeri binari e le operazioni sui bit
Walter Tross il

Probabilmente non dovresti definire una funzione all'interno di un'altra.
AMC

1
@ AlexanderCécile dipende . In questo caso penso che sia accettabile e migliora la pulizia, e comunque, è ciò che l'OP è stato suggerito dai suoi istruttori (vedi l'aggiornamento nella sua domanda).
Walter Tross,

1
@MiniMax le permutazioni di N articoli sono N !, ma i loro sottoinsiemi sono 2 ^ N: il primo elemento può essere nel sottoinsieme o meno: 2 possibilità; il secondo elemento può essere nel sottoinsieme o meno: × 2; il terzo elemento ... e così via, N volte.
Walter Tross,

1

Il seguente algoritmo fa questo:

  • ordina gli articoli
  • mette i membri pari nell'elenco a, dispari nell'elenco bper iniziare
  • sposta e scambia casualmente gli elementi tra ae bse la modifica è in meglio

Ho aggiunto delle dichiarazioni di stampa per mostrare i progressi nel tuo elenco di esempi:

# -*- coding: utf-8 -*-
"""
Created on Fri Dec  6 18:10:07 2019

@author: Paddy3118
"""

from random import shuffle, random, randint

#%%
items = [5, 6, 2, 10, 2, 3, 4]

def eq(a, b):
    "Equal enough"
    return int(abs(a - b)) == 0

def fair_partition(items, jiggles=100):
    target = sum(items) / 2
    print(f"  Target sum: {target}")
    srt = sorted(items)
    a = srt[::2]    # every even
    b = srt[1::2]   # every odd
    asum = sum(a)
    bsum = sum(b)
    n = 0
    while n < jiggles and not eq(asum, target):
        n += 1
        if random() <0.5:
            # move from a to b?
            if random() <0.5:
                a, b, asum, bsum = b, a, bsum, asum     # Switch
            shuffle(a)
            trial = a[0]
            if abs(target - (bsum + trial)) < abs(target - bsum):  # closer
                b.append(a.pop(0))
                asum -= trial
                bsum += trial
                print(f"  Jiggle {n:2}: Delta after Move: {abs(target - asum)}")
        else:
            # swap between a and b?
            apos = randint(0, len(a) - 1)
            bpos = randint(0, len(b) - 1)
            trya, tryb = a[apos], b[bpos]
            if abs(target - (bsum + trya - tryb)) < abs(target - bsum):  # closer
                b.append(trya)  # adds to end
                b.pop(bpos)     # remove what is swapped
                a.append(tryb)
                a.pop(apos)
                asum += tryb - trya
                bsum += trya - tryb
                print(f"  Jiggle {n:2}: Delta after Swap: {abs(target - asum)}")
    return sorted(a), sorted(b)

if __name__ == '__main__':
    for _ in range(5):           
        print('\nFinal:', fair_partition(items), '\n')  

Produzione:

  Target sum: 16.0
  Jiggle  1: Delta after Swap: 2.0
  Jiggle  7: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  4: Delta after Swap: 0.0

Final: ([2, 4, 10], [2, 3, 5, 6]) 

  Target sum: 16.0
  Jiggle  9: Delta after Swap: 3.0
  Jiggle 13: Delta after Move: 2.0
  Jiggle 14: Delta after Swap: 1.0
  Jiggle 21: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  7: Delta after Swap: 3.0
  Jiggle  8: Delta after Move: 1.0
  Jiggle 13: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  5: Delta after Swap: 0.0

Final: ([2, 4, 10], [2, 3, 5, 6]) 

Grazie mille, ma dovrei farlo senza importare nulla.
EddieEC,

1

Dal momento che so che devo generare tutti gli elenchi possibili, ho bisogno di creare una funzione di "aiuto" per aiutare a generare tutte le possibilità. Dopo averlo fatto, sono certo di verificare la differenza minima e la combinazione desiderata di liste con quella differenza minima è la soluzione desiderata.

La funzione di supporto è ricorsiva e controlla tutte le possibilità di combinazioni di elenchi.

def partition(ratings):

    def helper(ratings, left, right, aux_list, current_index):
        if current_index >= len(ratings):
            aux_list.append((left, right))
            return

        first = ratings[current_index]
        helper(ratings, left + [first], right, aux_list, current_index + 1)
        helper(ratings, left, right + [first], aux_list, current_index + 1)

    #l contains all possible sublists
    l = []
    helper(ratings, [], [], l, 0)
    set1 = []
    set2 = []
    #set mindiff to a large number
    mindiff = 1000
    for sets in l:
        diff = abs(sum(sets[0]) - sum(sets[1]))
        if diff < mindiff:
            mindiff = diff
            set1 = sets[0]
            set2 = sets[1]
    return (set1, set2)

Esempi: r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2]la partizione ottimale sarebbe: ([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])con una differenza di 1.

r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70], la partizione ottimale sarebbe: ([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])con una differenza di 0.


1
da quando mi hai chiesto: la tua soluzione va bene se stai imparando. Ha solo un problema, che per fortuna non affronta prima dell'altro problema che ha in comune con altre soluzioni: usa lo spazio esponenziale (O (n2ⁿ)). Ma il tempo esponenziale si presenta come un problema molto prima. Tuttavia, evitare di usare lo spazio esponenziale sarebbe facile.
Walter Tross,

1

Ecco un esempio abbastanza elaborato, inteso per scopi educativi piuttosto che per prestazioni. Presenta alcuni concetti interessanti di Python come la comprensione dell'elenco e i generatori, nonché un buon esempio di ricorsione in cui i casi marginali devono essere controllati in modo appropriato. Le estensioni, ad esempio solo le squadre con un numero uguale di giocatori sono valide, sono facili da implementare nelle singole funzioni appropriate.

def listFairestWeakTeams(ratings):
    current_best_weak_team_rating = -1
    fairest_weak_teams = []
    for weak_team in recursiveWeakTeamGenerator(ratings):
        weak_team_rating = teamRating(weak_team, ratings)
        if weak_team_rating > current_best_weak_team_rating:
            fairest_weak_teams = []
            current_best_weak_team_rating = weak_team_rating
        if weak_team_rating == current_best_weak_team_rating:
            fairest_weak_teams.append(weak_team)
    return fairest_weak_teams


def recursiveWeakTeamGenerator(
    ratings,
    weak_team=[],
    current_applicant_index=0
):
    if not isValidWeakTeam(weak_team, ratings):
        return
    if current_applicant_index == len(ratings):
        yield weak_team
        return
    for new_team in recursiveWeakTeamGenerator(
        ratings,
        weak_team + [current_applicant_index],
        current_applicant_index + 1
    ):
        yield new_team
    for new_team in recursiveWeakTeamGenerator(
        ratings,
        weak_team,
        current_applicant_index + 1
    ):
        yield new_team


def isValidWeakTeam(weak_team, ratings):
    total_rating = sum(ratings)
    weak_team_rating = teamRating(weak_team, ratings)
    optimal_weak_team_rating = total_rating // 2
    if weak_team_rating > optimal_weak_team_rating:
        return False
    elif weak_team_rating * 2 == total_rating:
        # In case of equal strengths, player 0 is assumed
        # to be in the "weak" team
        return 0 in weak_team
    else:
        return True


def teamRating(team_members, ratings):
    return sum(memberRatings(team_members, ratings))    


def memberRatings(team_members, ratings):
    return [ratings[i] for i in team_members]


def getOpposingTeam(team, ratings):
    return [i for i in range(len(ratings)) if i not in team]


ratings = [5, 6, 2, 10, 2, 3, 4]
print("Player ratings:     ", ratings)
print("*" * 40)
for option, weak_team in enumerate(listFairestWeakTeams(ratings)):
    strong_team = getOpposingTeam(weak_team, ratings)
    print("Possible partition", option + 1)
    print("Weak team members:  ", weak_team)
    print("Weak team ratings:  ", memberRatings(weak_team, ratings))
    print("Strong team members:", strong_team)
    print("Strong team ratings:", memberRatings(strong_team, ratings))
    print("*" * 40)

Produzione:

Player ratings:      [5, 6, 2, 10, 2, 3, 4]
****************************************
Possible partition 1
Weak team members:   [0, 1, 2, 5]
Weak team ratings:   [5, 6, 2, 3]
Strong team members: [3, 4, 6]
Strong team ratings: [10, 2, 4]
****************************************
Possible partition 2
Weak team members:   [0, 1, 4, 5]
Weak team ratings:   [5, 6, 2, 3]
Strong team members: [2, 3, 6]
Strong team ratings: [2, 10, 4]
****************************************
Possible partition 3
Weak team members:   [0, 2, 4, 5, 6]
Weak team ratings:   [5, 2, 2, 3, 4]
Strong team members: [1, 3]
Strong team ratings: [6, 10]
****************************************

1

Dato che vuoi persino squadre, conosci il punteggio target delle valutazioni di ogni squadra. Questa è la somma dei voti divisa per 2.

Quindi il seguente codice dovrebbe fare quello che vuoi.

from itertools import combinations

ratings = [5, 6, 2, 10, 2, 3, 4]

target = sum(ratings)/2 

difference_dictionary = {}
for i in range(1, len(ratings)): 
    for combination in combinations(ratings, i): 
        diff = sum(combination) - target
        if diff >= 0: 
            difference_dictionary[diff] = difference_dictionary.get(diff, []) + [combination]

# get min difference to target score 
min_difference_to_target = min(difference_dictionary.keys())
strong_ratings = difference_dictionary[min_difference_to_target]
first_strong_ratings = [x for x in strong_ratings[0]]

weak_ratings = ratings.copy()
for strong_rating in first_strong_ratings: 
    weak_ratings.remove(strong_rating)

Produzione

first_strong_ratings 
[6, 10]

weak_rating 
[5, 2, 2, 3, 4]

Ci sono altre divisioni che hanno lo stesso che fairnesssono tutte disponibili per trovare all'interno della tupla strong_ratings, ho solo scelto di guardare il primo in quanto questo esisterà sempre per qualsiasi elenco di voti che passi (fornito len(ratings) > 1).


La sfida di questa domanda era di non importare nulla come ho detto nella mia domanda. Grazie per il tuo contributo!
EddieEC,

0

Una soluzione avida potrebbe produrre una soluzione non ottimale. Ecco una soluzione avida abbastanza semplice, l'idea è quella di ordinare l'elenco in ordine decrescente al fine di ridurre l'effetto dell'aggiunta di voti nel bucket. La valutazione verrà aggiunta a quel bucket la cui somma totale della valutazione è inferiore

lis = [5, 6, 2, 10, 2, 3, 4]
lis.sort()
lis.reverse()

bucket_1 = []
bucket_2 = []

for item in lis:
    if sum(bucket_1) <= sum(bucket_2):
        bucket_1.append(item)
    else:
        bucket_2.append(item)

print("Bucket 1 : {}".format(bucket_1))
print("Bucket 2 : {}".format(bucket_2))

Produzione :

Bucket 1 : [10, 4, 2]
Bucket 2 : [6, 5, 3, 2]

Modificare:

Un altro approccio sarà quello di generare tutti i possibili sottoinsiemi dell'elenco. Supponiamo che tu abbia l1, che è uno dei sottoinsiemi dell'elenco, quindi puoi facilmente ottenere l'elenco l2 in modo tale che l2 = list (originale) - l1. Il numero di tutti i possibili sottogruppi dell'elenco di dimensioni n è 2 ^ n. Possiamo denotarli come seq di un numero intero compreso tra 0 e 2 ^ n -1. Prendiamo un esempio, supponiamo di avere list = [1, 3, 5], quindi nessuna delle combinazioni possibili è 2 ^ 3 cioè 8. Ora possiamo scrivere tutte le combinazioni come segue:

  1. 000 - [] - 0
  2. 001 - [1] - 1
  3. 010 - [3] - 2
  4. 011 - [1,3] - 3
  5. 100 - [5] - 4
  6. 101 - [1,5] - 5
  7. 110 - [3,5] - 6
  8. 111 - [1,3,5] - 7 e l2, in questo caso, possono essere facilmente ottenuti prendendo xor con 2 ^ n-1.

Soluzione:

def sum_list(lis, n, X):
    """
    This function will return sum of all elemenst whose bit is set to 1 in X
    """
    sum_ = 0
    # print(X)
    for i in range(n):
        if (X & 1<<i ) !=0:
            # print( lis[i], end=" ")
            sum_ += lis[i]
    # print()
    return sum_

def return_list(lis, n, X):
    """
    This function will return list of all element whose bit is set to 1 in X
    """
    new_lis = []
    for i in range(n):
        if (X & 1<<i) != 0:
            new_lis.append(lis[i])
    return new_lis

lis = [5, 6, 2, 10, 2, 3, 4]
n = len(lis)
total = 2**n -1 

result_1 = 0
result_2 = total
result_1_sum = 0
result_2_sum = sum_list(lis,n, result_2)
ans = total
for i in range(total):
    x = (total ^ i)
    sum_x = sum_list(lis, n, x)
    sum_y = sum_list(lis, n, i)

    if abs(sum_x-sum_y) < ans:
        result_1 =  x
        result_2 = i
        result_1_sum = sum_x
        result_2_sum = sum_y
        ans = abs(result_1_sum-result_2_sum)

"""
Produce resultant list
"""

bucket_1 = return_list(lis,n,result_1)
bucket_2 = return_list(lis, n, result_2)

print("Bucket 1 : {}".format(bucket_1))
print("Bucket 2 : {}".format(bucket_2))

Produzione :

Bucket 1 : [5, 2, 2, 3, 4]
Bucket 2 : [6, 10]

Ciao, se leggi la mia domanda originale, potresti vedere che ho già usato il metodo Greedy ed è stato respinto. Grazie per il tuo contributo però!
EddieEC,

@EddieEC qual è il vincolo su n (lunghezza dell'array). Se si desidera generare tutte le combinazioni possibili, si tratta sostanzialmente di un problema di somma di sottoinsieme, che è un problema NP completo.
vkSinha,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.