【问题标题】:Grouping a list of integers into two groups将整数列表分为两组
【发布时间】:2014-09-22 14:13:28
【问题描述】:

给定一个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";
        }
    

解决方案 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";
    

问题

上面提到的两种解决方案都给出了错误的答案。我不明白他们在哪些情况下失败了。

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

【问题讨论】:

    标签: algorithm greedy


    【解决方案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-hard 问题,不能在多项式时间内解决。但是,存在一个基于动态规划的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 的子集。

    【讨论】:

      【解决方案2】:

      快速尝试——A 的总和必须

      你能提供更多的测试用例吗?或者只是我的算法不起作用的情况。

      【讨论】:

      • 考虑 s=6,n=3 and elements as 2,5,5 ,它通过了你的案例,但答案仍然是 NO
      【解决方案3】:

      Group1 =

      如果数字总和 =

      返回真

      其他

      返回错误

      【讨论】:

      • s=6,n=3 and elements as 2,5,5 ,数字总和
      【解决方案4】:

      首先对数字进行排序。第一组 (sum1) 由最大数 + 小数组成。其他号码进入第二组。

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

      对数组进行升序排序

      我 =1; sum1 = a[n]; sum2=0;

      而 ( sum1 + a[i] =

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

      我 ++

      结束

      对于 j = i 到 n -1

      sum2 = sum2 + a[j]

      结束

      如果 (sum1 =

      否则返回false;

      【讨论】:

      • 这与问题中的Solution 1 相同。
      • 这是恭顺的。该解决方案开始从最大元素到最小元素求和。但是我将最大的元素与第一个最小的和第二个最小的元素相加......
      猜你喜欢
      • 1970-01-01
      • 2012-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多