将一组数字分成两部分,差别最小

时间:2011-02-04 14:48:06

标签: algorithm partitioning

将一组数字(n个数字)划分为2个子集,以便子集1中的数字总和与子集2中的数字总和的差异最小。此外,还需要以下条件:

  • 如果n = 2k,则每个子集都有k个成员
  • 如果n = 2k + 1,则一个子集具有k个成员,另一个子集具有k + 1个成员。

2 个答案:

答案 0 :(得分:3)

这个问题是NP完全的。 http://en.wikipedia.org/wiki/Partition_problem 你必须通过蛮力找到解决方案。

(任意大小的分区的分区问题等同于相同大小的分区的问题 - 只需向所有数字添加一个大的值C,并要求差异小于C ...)

您可能还想查看http://en.wikipedia.org/wiki/Subset_sum_problem

答案 1 :(得分:0)

此答案是从http://www.careercup.com/question?id=10244832

复制而来的

本质上是NP-hard,解决方案属于复数为O(n ^ 2W)的伪多项式时间算法,其中n =元素数,W =元素之和。

//constraints: n is even
void fun (int items[], int n)
{
    int total = accumulate (items, items+n, 0) / 2;
    int maxSubsetSz = n/2 ;

    vector< vector<int> > T (maxSubsetSz+1, vector<int> (total+1, 0) );

    //T[i][j] is set if there exists subset of size i that sum up to j
    T[0][0] = 1;    

    for(int i = 0; i < n; i++) //consider taking i-th item      
       for(int k = maxSubsetSz-1; k >= 0; k--) //each item must be taken once, hence loop backwards
           for(int j = 0; j <= total-items[i]; j++)  
               if ( T[k][j] && items[i]+j <= total )                        
                     T [k+1] [j+items[i]] = 1;

    for(int j = total; j >= 1; j--)
       if ( T [maxSubsetSz][j] ) {
        cout << "sum : " << j << endl; 
        break;
    }
}

@hugomg提供的答案具有相同的时间复杂度,因为大值C应至少与W(=元素之和)一样大,从而使背包问题的时间复杂度= O(n *(W +) nW))= O(n ^ 2 * W)