2010-11-18 12 views
12

Folks,diferencia mínima entre la suma de dos subconjuntos

encontramos con un problema ... encontraron esta intersting ... estoy modificando un poco solo tu pep para arriba.

Dado un conjunto de enteros (rango 0-500), encuentre la diferencia mínima entre la suma de dos subconjuntos que pueden formarse dividiéndolos casi por igual. (decir recuento de enteros es n, si n es par, cada conjunto debe tener n/2 elementos y si n es impar, un conjunto tiene (n-1)/2 elementos y otro tiene (n + 1)/2 elementos)

muestra imput: 1 2 3 4 5 6

diferencia mínima = 1 (subconjuntos siendo 1 4 6 y 2 3 5)

entrada de la muestra 2: [1 1 1 1 2 2 2 2]

diferencia mínima = 0 (subconjuntos siendo 1 1 2 2 1 1 y 2 2)

hay un enfoque DP para este problema.

Gracias chicos ...

raj ...

+1

destacando: el PO no está interesado en la construcción ** ** los subconjuntos, sólo en la obtención del mínimo.Si es posible hacerlo sin construir los subconjuntos es un tema abierto, por supuesto. –

Respuesta

-1
from random import uniform 
    l=[int(uniform(0, 500)) for x in xrange(15)] 
    l.sort() 
    a=[] 
    b=[] 
    a.append(l.pop()) 
    while l: 
     if len(a) > len(b): 
      b.append(l.pop()) 
     elif len(b) > len(a): 
      a.append(l.pop()) 
     elif sum(a) > sum(b): 
      b.append(l.pop()) 
     else: 
      a.append(l.pop()) 

    print a, b 
    print sum(a), sum(b) 
    print len(a), len(b) 

Siguiente paso me gustaría tratar de encontrar un par de números de las listas opuestas con una diferencia media de la diferencia de las sumas (o cerca eso) y cambiarlos.

+0

No creo que sea enteros 0-500, solo un subconjunto ... –

+1

Puedo tener cualquier cantidad de elementos, donde cada elemento está dentro del rango (1, 500) '. Si l es el rango (1,500) la diferencia es 0 o 1. –

+0

Gracias por la entrada. Solucionado eso. – cababunga

1

Una buena manera de pensar sería, si tuviera una solución de DP para este problema, ¿podría usarla para responder la suma de subconjuntos en un período de tiempo P? Si es así, entonces su solución de DP probablemente no sea correcta.

+0

hmmm @Kevin bt también necesitamos pensar en dividirlo en partes iguales, rito ... así que también puede ser una partición ... bt estamos interesados ​​en la diferencia solamente ... – Rajan

+1

Si los números enteros son acotados (como rango 0-500 como aquí) puede resolver la suma de subconjuntos en tiempo polinomial. http://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution – adl

9

Este problema se parece a la "partición equilibrada".

Puede usar un enfoque DP para construir un algoritmo de tiempo pseudopolinomial que resuelva la partición balanceada. Vea el problema 7 en http://people.csail.mit.edu/bdean/6.046/dp/

Parece que podría tener un enfoque similar.

+0

adl, sí al particionarlo en los dos conjuntos, conoceremos el equilibrio ... ¿hay alguna manera de encontrar solo la diferencia mínima sin construir realmente el subconjuntos ... – Rajan

+0

@Rajan: Sí, hay una heurística que usa un montón mínimo para almacenar la diferencia de los números en un bucle hasta que te queda un solo número. De esta manera puede obtener la mínima diferencia posible. Consulte https://en.wikipedia.org/wiki/Partition_problem#CITEREFKarmarkarKarp1982 para obtener más información. – uyetch

0

Parece ser una instancia del Partition problem, que es NP-Complete.

De acuerdo con el artículo de Wikipedia, hay una solución de programación dinámica de tiempo seudo-polinomial.

2

He resuelto recientemente este problema usando la Programación Dinámica en C++. No he modificado el código para responder tu pregunta. Pero cambiar algunas constantes y poco código debería hacer.

El siguiente código lee y resuelve N problemas. Cada problema tiene algunas personas (en su caso, número de enteros) y sus pesos (valores enteros). Este código intenta dividir el conjunto en 2 grupos con la diferencia de ser mínimo.

#include <iostream> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define MAX_PEOPLE 100 
#define MAX_WEIGHT 450 
#define MAX_WEIGHT_SUM MAX_PEOPLE*MAX_WEIGHT 
using namespace std; 

int weights[MAX_PEOPLE]; 
//bool table[MAX_PEOPLE + 1][MAX_WEIGHT_SUM + 1]; 

bool** create2D(int x, int y) { 
    bool **array = new bool*[x]; 
    for (int i = 0; i < x; ++i) { 
     array[i] = new bool[y]; 
     memset(array[i], 0, sizeof(bool)*y); 
    } 
    return array; 
} 

void delete2D(int x, int y, bool **array) { 
    for (int i = 0; i < x; ++i) { 
     delete[] array[i]; 
    } 
    delete[] array; 
} 

void memset2D(int x, int y, bool **array) { 
    for(int i = 0; i < x; ++i) 
     memset(array[i], 0, sizeof(bool)*y); 
} 

int main(void) { 
    int n, N, W, maxDiff, teamWeight, temp; 
    int minWeight = MAX_WEIGHT, maxWeight = -1; 
    cin >> N; 
    while(N--) { 
     cin >> n; 
     W = 0; 
     for(int i = 0; i < n; ++i) { 
      cin >> weights[i]; 
      if(weights[i] < minWeight) 
       minWeight = weights[i]; 
      if(weights[i] > maxWeight) 
       maxWeight = weights[i]; 

      W += weights[i]; 
     } 
     int maxW = maxWeight + (W>>1); 
     int maxn = n>>1; 
     int index = 0; 
    /* 
     table[j][i] = 1 if a team of j people can form i weight 
         from K people, where k is implicit in loop 
     table[j][i] = table[j-1][i-weight[j]] if i-weight[j] >=0 
    */ 
     bool **table = create2D(maxn+1, maxW+1); 
     //memset2D(maxn+1, maxW+1, table); 
     //memset(table, 0, sizeof(table)); 
     table[0][0] = true; 
     /* for k people what can be formed?*/ 
     for(int k = 0; k < n; ++k) { 
      /* forming team of size j out of k people*/ 
      for(int j = min(k, maxn) ; j >= 1; --j) { 
       /* using j people out of k, can I make weight i?*/ 
       for(int i = maxW; i >=minWeight ; --i) { 
        if (table[j][i] == false) { 
         /*do not consider k if more than allowable*/ 
         index = i - weights[k]; 
         if (index < 0) break; 
         /*if without adding k, we can make the weight 
          limit with less than one person then one can 
          also make weight limit by adding k.*/ 
         table[j][i] = table[j-1][index]; 
        } /*outer if ends here*/ 
       } /* ith loop */ 
      } /* jth loop */ 
     } /* kth loop */ 

     maxDiff = MAX_WEIGHT_SUM ; 
     teamWeight = 0; 
     for(int i = 0; i <= maxW; ++i) { 
      if (table[n/2][i]) { 
       temp = abs(abs(W - i) - i); 
       if (temp < maxDiff) { 
        maxDiff = temp; 
        teamWeight = i; 
       } 
      } 
     } 
     delete2D(n+1, maxW+1, table); 
     teamWeight = min(teamWeight, W-teamWeight); 
      cout << teamWeight << " " << W - teamWeight << endl; 
     if(N) 
      cout << endl; 
    } 
     return 0; 
} 
0

He escrito este programa en C++ suponiendo que la suma máxima podría ser 10000.

#include <iostream> 
#include <vector> 
#include <memory> 
#include <cmath> 

using namespace std; 
typedef vector<int> VecInt; 
typedef vector<int>::size_type VecSize; 
typedef vector<int>::iterator VecIter; 

class BalancedPartition { 
public: 
    bool doBalancePartition(const vector<int>*const & inList, int sum) { 
     int localSum = 0, j; 
     bool ret = false; 
     int diff = INT_MAX, ans=0; 

     for(VecSize i=0; i<inList->size(); ++i) { 
      cout<<(*inList)[i]<<"\t"; 
     } 
     cout<<endl; 
     for(VecSize i=0; i<inList->size(); ++i) { 
      localSum += (*inList)[i]; 
     } 
     M.reset(new vector<int>(localSum+1, 0)); 
     (*M)[0] = 1; 
     cout<<"local sum "<<localSum<<" size of M "<<M->size()<<endl; 

     for(VecSize k=0; k<inList->size(); ++k) { 
      for(j=localSum; j>=(*inList)[k]; --j) { 
       (*M)[j] = (*M)[j]|(*M)[j-(*inList)[k]]; 
       if((*M)[j]) { 
        if(diff > abs(localSum/2 -j)) { 
         diff = abs(localSum/2 -j); 
         ans = j; 
        } 
       } 
      } 
     } 
     mMinDiffSubSumPossible = abs(localSum - 2*ans); 
     return ret; 
    } 

    friend ostream& operator<<(ostream& out, const BalancedPartition& bp) { 
     out<<"Min diff "<<bp.mMinDiffSubSumPossible; 
     return out; 
    } 
    BalancedPartition(): mIsSumPossible(false), mMinDiffSubSumPossible(INT_MAX) { 

    } 
private: 
    shared_ptr<vector<int> > M; 
    bool mIsSumPossible; 
    int mMinDiffSubSumPossible; 
    static const int INT_MAX = 10000; 
}; 

int main(void) { 
    shared_ptr<BalancedPartition> bp(new BalancedPartition()); 
    int arr[] = {4, 12, 13, 24, 35, 45}; 
    vector<int> inList(arr, arr + sizeof(arr)/sizeof(arr[0])); 
    bp->doBalancePartition(&inList, 0); 
    cout<<*bp; 
    return 0; 
} 
Cuestiones relacionadas