将整数列表分组为两组

时间:2014-09-21 21:16:24

标签: algorithm greedy

如果列出了n个数字和总和s,请将这些数字分组到two个组中,以使每个组中的数字总和为less than or equal to s。如果可以分组,请打印YES,如果无法分组,请打印NO

例如,如果n=3 , s=4n数字为2,4,2。 在这种情况下,输出为YES,因为可以形成的两个组是(2,2) and (4)

我的解决方案如下。

A是包含n个数字的整数数组。

first group包含第一组中的元素总和。

second group包含第二组中元素的总和。

解决方案1 ​​

  1. 按降序对数组进行排序。
  2. 继续向第二组添加数字,直到该组中的元素总和小于或等于s
  3. 将第一组的总和计算为sum of all elements减去sum of elements in second group
  4. 如果每个组中的元素总和小于或等于s,则打印YES否则打印NO

        qsort (A, n, sizeof(int),compare);
        int second_group=0;
        f=0;
        for(i=0;i<n;++i)
        {
            if((second_group+A[i])==s)
            {
                f=1;
                break;
            }
            else if((second_group+A[i])<s)
            {
                second_group+=A[i];
            }
    
        }
        int first_group=sum_of_all_elements-second_group;
        if(f==1)
        {
            cout<<"YES\n";
        }
        else if ((second_group<=s) && (first_group<=s))
        {
            cout<<"YES\n";
        }
        else
        {
            cout<<"NO\n";
        }
    
  5. 解决方案2 使用Greedy approach

    1. 按降序对数组进行排序。
    2. 将数组中的第一个元素添加到第一个组。
    3. 迭代其余元素,并将每个元素添加到具有最小总和的组中。
    4. 如果两个组的元素总和等于sum_of_all_elements,则打印YES否则打印NO

          qsort (A, n, sizeof(int),compare);
          int first_group=0,second_group=0;
          f=0;
          first_group=A[0];
          for(i=1;i<n;++i)
          {
              if(first_group<second_group)
              {
                  if((first_group+A[i])<=s)
                  first_group+=A[i];
              }
              else
              {
                  if((second_group+A[i])<=s)
                  second_group+=A[i];
              }
          }
          if((first_group+second_group)==sum_of_all_elements)
              cout<<"YES\n";
          else
              cout<<"NO\n";
      
    5. 问题

      上述两种解决方案都给出了错误答案。我无法理解他们失败的场景。

      如果有人可以帮助我解决这个问题的任何其他替代解决方案,那就太棒了。

4 个答案:

答案 0 :(得分:1)

您假设所有最小的元素都在一个组中,这不一定是真的。

采用以下示例:

array = {1, 2, 4, 6} , s = 7

对于上述情况,您的两种解决方案都会产生错误的输出。

首先让我澄清一下你要解决的问题。您正在尝试解决Subset Sum Problem的修改版本。让我为你重新解释一下这个问题:

1. Give an array A and a sum S. Find the subset of A with the largest sum S1 
   such that  S1 <= S. (We want the largest sum because it will give the 
   smallest possible sum for the rest of the elements).

2. Now the sum of the rest of the elements is S2 = TotalSum - S1. If S2 <= S, 
   print YES otherwise print NO.

子集和问题是NP难问题,不能在多项式时间内求解。但是,存在基于动态编程的Pseudo-Polynomial Time算法。有关伪多项式解,请参阅Subset Sum ProblemDynamic Programming: Subset Sum。这个想法是这样的:

   Use dynamic programming to calculate whether there is a solution to the 
   subset sum problem for sum = S. If there is a solution, then report YES 
   if TotalSum - S <= S. Otherwise pick the largest sum that exists in the 
   DP table (just select the last row with subset sum = True entry in the 
   last column). Let this sum be S1.
   If S1 <= S report YES otherwise NO.

通过在构建DP时记住额外信息,您还可以记住导致您为第一个子集选择的总和S1的子集。

答案 1 :(得分:0)

快速尝试 - A的总和必须<= 2 * s。 A中最大的元素必须是&lt; = s。

你能提供更多的测试案例吗?或者只是我的algh无法工作的情况。

答案 2 :(得分:0)

Group1 =&lt; s和group2 =&lt;小号 所以 group1 + group =数字之和=&lt; 2 * S 所以我建议使用简单的算法,

如果数字总和=&lt; 2 * s

返回true

否则

返回false

答案 3 :(得分:0)

首先对数字进行排序。第一组(sum1)由最大数字组成+与小数字一样多。其他数字转到第二组。

如果数字总和> 2 * s返回false;

按升序对数组进行排序

i = 1; sum1 = a [n]; SUM2 = 0;

while(sum1 + a [i] =&lt; s)

总和1 =总和1 + a [i]

i ++

结束时

表示j = i到n -1

sum2 = sum2 + a [j]

结束

如果(sum1 =&lt; s)和(sum2 =&lt; s)返回true

否则返回false;