【问题标题】:Balanced partition平衡分区
【发布时间】:2012-09-28 16:05:19
【问题描述】:

我知道这里讨论了很多,但我正在努力解决这个问题。

我们有一组数字,例如 [3, 1, 1, 2, 2, 1],我们需要将其分成两个子集,因此每个和都相等或差异最小。

我见过wikipedia entry、这个page(问题7)和一个blog entry

但是列出的每个算法都只给出 YES/NO 结果,我真的不明白如何使用它们打印出两个子集(例如 S1 = {5, 4} 和 S2 = {5, 3, 3}) .我在这里错过了什么?

【问题讨论】:

  • 您可能可以通过向后遍历计算表来获取子集。这是动态规划问题中的标准策略。
  • 好吧,你能详细说明一下吗?
  • 您的列表中是否有最大数量的数字,如果有,它是多少?如果算法产生的解决方案非常接近最优但不一定是最优的,那是否足够好?
  • 没有最大数量,我真的需要最好的解决方案 :-)

标签: algorithm


【解决方案1】:

伪多项式算法旨在为决策问题提供答案,而不是优化问题。但是请注意,the example 中布尔值表的最后一行表示当前集合能够求和为 N/2。

在最后一行中,取布尔值为true 的第一列。然后,您可以检查给定列中集合的实际值是多少。如果集合总和值为 N/2,则您已找到分区的第一组。否则,您必须检查哪个集合能够与 N/2 不同。您可以使用与上述相同的方法,这次是为了区别 d

【讨论】:

    【解决方案2】:

    这将是 O(2^N)。这里没有使用动态规划。您可以在函数执行后打印 result1、result2 和差异。我希望这会有所帮助。

    vector<int> p1,p2;
    vector<int> result1,result2;
    vector<int> array={12,323,432,4,55,223,45,67,332,78,334,23,5,98,34,67,4,3,86,99,78,1};
    
    void partition(unsigned int i,long &diffsofar, long sum1,long sum2)
    {
        if(i==array.size())
        {
            long diff= abs(sum1 - sum2);
            if(diffsofar > diff)
            {
                result1 =  p1;
                result2 = p2;
                diffsofar = diff;
            }
            return;
        }
    
        p1.push_back(array[i]);
        partition(i+1,diffsofar,sum1+array[i],sum2);
        p1.pop_back();
    
        p2.push_back(array[i]);
        partition(i+1,diffsofar,sum1,sum2+array[i]);
        p2.pop_back();
    
        return;
    }
    

    【讨论】:

      【解决方案3】:

      我最近遇到了同样的问题,我发布了一个关于它的问题(这里:Variant of Knapsack)。我的情况的不同之处在于结果子集的大小必须相同(如果原始集合具有偶数个元素)。为了确保这一点,我在@Sandesh Kobal 答案中添加了几行;

      void partition(unsigned int i,long &diffsofar, long sum1,long sum2)
      {
          int maxsize = (array.size()+1)/2;
      
          if(p1.size()>maxsize)
              return;
      
          if(p2.size()>maxsize)
              return;
      
          if(i==array.size())
          {
              ...
      

      另外,在两次调用partition 之后,我添加了if(diffsofar==0) return;。如果我们已经找到了最佳解决方案,那么继续寻找是没有意义的……

      【讨论】:

        【解决方案4】:

        我看到的所有文章都采用动态编程方法。我们真的需要一个吗?

        假设给定的数组是arr

        使用以下算法:

        1. 按降序对数组进行排序
        2. 创建两个空数组,a = []b = []
        3. sum_a = sum_b = 0
        for x in arr:
            if sum_a > sum_b:
                b.append(x)
                sum_b += x
            else:
                a.append(x)
                sum_a += x
        

        sum_asum_b 之间的绝对差异将是两个子集之间的最小可能差异。


        考虑arr = [3,1,1,2,2,1]

        对数组进行排序:arr = [3,2,2,1,1,1]

        a = [], b = []
        a = [3], b = []
        a = [3], b = [2]
        a = [3], b = [2,2]
        a = [3,1], b = [2,2]
        a = [3,1,1], b = [2,2]
        a = [3,1,1], b = [2,2,1]
        

        sa = 5, sb = 5

        最小差异:5 - 5 = 0

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-25
          • 1970-01-01
          • 2021-09-02
          • 2011-02-21
          相关资源
          最近更新 更多