2010-11-18 42 views
12

Folks,sự khác biệt tối thiểu giữa tổng của hai tập hợp con

gặp một vấn đề ... tìm thấy sự liên kết này ... đang sửa đổi nó một chút chỉ cần tuôn nó lên.

Cho một tập hợp các số nguyên (khoảng 0-500), tìm sự khác biệt tối thiểu giữa tổng của hai tập con có thể được tạo thành bằng cách tách chúng gần bằng nhau. (nói số nguyên là n, nếu n là chẵn, mỗi bộ phải có n/2 phần tử và nếu n là lẻ, một bộ có (n-1)/2 phần tử và các phần tử khác có (n + 1)/2)

mẫu imput: 1 2 3 4 5 6

tối thiểu chênh lệch = 1 (tập con là 1 4 6 và 2 3 5)

mẫu đầu vào 2: [1 1 1 1 2 2 2 2]

tối thiểu chênh lệch = 0 (các tập con là 1 1 2 2 và 1 1 2 2)

là có cách tiếp cận DP cho vấn đề này.

Thanks guys ...

raj ...

+1

Nhấn mạnh: OP là không quan tâm đến việc xây dựng ** ** các tập con, chỉ trong việc có được mức tối thiểu.Cho dù nó có thể làm như vậy mà không xây dựng các tập con là một vấn đề mở của khóa học. –

Trả lời

-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) 

Bước tiếp theo tôi sẽ cố gắng để tìm một cặp số từ danh sách đối diện với sự khác biệt một nửa của sự khác biệt của các khoản tiền (hoặc gần đó) và trao đổi chúng.

+0

Tôi không nghĩ rằng đó là tất cả các số nguyên 0-500, chỉ là một tập con ... –

+1

l có thể có bất kỳ số phần tử nào, trong đó mọi phần tử nằm trong phạm vi (1, 500) '. Nếu l là phạm vi (1.500), chênh lệch là 0 hoặc 1. –

+0

Cảm ơn đầu vào. Sửa lỗi đó. – cababunga

1

Một cách hay để nghĩ về nó là, nếu bạn có giải pháp DP cho vấn đề này, bạn có thể sử dụng nó để trả lời tổng tập hợp con trong một khoảng thời gian P không? Nếu vậy thì giải pháp DP của bạn có lẽ không chính xác.

+0

hmmm @Kevin bt chúng ta cũng cần tu nghĩ rằng tách nó thành phần bằng nhau, nghi thức ... để nó có thể phân vùng ... bt chúng ta chỉ quan tâm đến sự khác biệt .. – Rajan

+1

Nếu các số nguyên bị chặn (như trong khoảng 0-500 như ở đây), bạn có thể giải quyết tập hợp con tổng trong thời gian đa thức. http://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution – adl

9

Sự cố này trông gần giống như "phân vùng cân bằng".

Bạn có thể sử dụng phương pháp DP để xây dựng thuật toán thời gian đa thức giả để giải quyết phân vùng cân bằng. Xem sự cố 7 tại http://people.csail.mit.edu/bdean/6.046/dp/

Có vẻ như bạn có thể có cách tiếp cận tương tự.

+0

adl, yes bằng cách phân vùng nó thành hai bộ chúng ta sẽ biết số dư ... có cách nào để chỉ tìm ra sự khác biệt tối thiểu mà không thực sự xây dựng tập hợp con ... – Rajan

+0

@ Rajan: Có, có một heuristic sử dụng một heap min để lưu trữ sự khác biệt của các con số trong một vòng lặp cho đến khi bạn còn lại với một số duy nhất. Bằng cách này bạn có thể nhận được sự khác biệt tối thiểu có thể. Xem https://en.wikipedia.org/wiki/Partition_problem#CITEREFKarmarkarKarp1982 để biết thêm thông tin. – uyetch

0

Điều này có vẻ là một phiên bản của Partition problem, là NP-Complete.

Theo bài viết trên Wikipedia, có một giải pháp lập trình động thời gian đa thức giả.

2

Tôi đã giải quyết vấn đề này gần đây bằng cách sử dụng Lập trình động trong C++. Tôi chưa sửa đổi mã để trả lời câu hỏi của bạn. Nhưng thay đổi một số hằng số và ít mã nên làm.

Đoạn mã dưới đây đọc và giải quyết các sự cố N. Mỗi sự cố có một số người (trong số trường hợp của bạn là số nguyên) và trọng số của chúng (giá trị số nguyên). Mã này cố gắng chia bộ thành 2 nhóm với sự khác biệt là tối thiểu.

#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

Tôi đã viết chương trình này trong C++ giả định rằng max tổng thể là 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; 
} 
Các vấn đề liên quan