数组的最小和分区

时间:2018-08-06 15:47:44

标签: c algorithm dynamic-programming

问题陈述:

给出一个数组,任务是将其分为两组S1和S2,以使它们的和之间的绝对差最小。

示例输入

[1,6,5,11] => 1。这两个子集为{1,5,6}{11},总和为1211。因此答案是1

[36,7,46,40] => 23。这两个子集为{7,46}{36,40},总和为5376。因此答案是23

约束

  

1 <=数组大小<= 50

     

1 <= a [i] <= 50

我的努力:

int someFunction(int n, int *arr) {
    qsort(arr, n, sizeof(int), compare);// sorted it for simplicity
    int i, j;
    int dp[55][3000]; // sum of the array won't go beyond 3000 and size of array is less than or equal to 50(for the rows) 

    // initialize
    for (i = 0; i < 55; ++i) {
        for (j = 0; j < 3000; ++j)
            dp[i][j] = 0;
    }

    int sum = 0;
    for (i = 0; i < n; ++i)
        sum += arr[i];

    for (i = 0; i < n; ++i) {
        for (j = 0; j <= sum; ++j) {
            dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
            if (j >= arr[i])
                dp[i + 1][j + 1] = max(dp[i + 1][j + 1], arr[i] + dp[i][j + 1 - arr[i]]);
        }
    }

    for (i = 0; i < n; ++i) {
        for (j = 0; j <= sum; ++j)
            printf("%d ", dp[i + 1][j + 1]);
        printf("\n");
    }
    return 0;// irrelevant for now as I am yet to understand what to do next to get the minimum. 
}

输出

比方说输入[1,5,6,11],我得到的dp数组输出如下。

0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
0 1 1 1 1 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 12 12 12 12 12 12 12 12 
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 16 17 18 18 18 18 22 23 

现在,如何决定两个子集以获得最小值?

PS-我已经看过这个link,但对于像我这样的DP初学者来说,解释还不够好。

3 个答案:

答案 0 :(得分:4)

您必须为subset sum解决SumValue = OverallSum / 2问题

请注意,您无需解决任何优化问题(如在代码中使用max操作所示)。

仅用可能的和填充大小为(SumValue + 1)的线性表(1D数组A),获得最接近最后一个像元的非零结果(向后扫描A)wint索引M并将最终结果计算为abs(OverallSum - M - M)

首先,将第0个条目设置为1。 然后从头到尾对每个源数组项D[i]扫描数组A

A[0] = 1;
for (i = 0; i < D.Length(); i++)
  {
    for (j = SumValue; j >= D[i]; j--)  
      {
        if (A[j - D[i]] == 1)   
       // we can compose sum j from D[i] and previously made sum
             A[j] = 1;
       }
   }  

例如,D = [1,6,5,11]您拥有SumValue = 12,建立数组A[13],并计算可能的总和

A array after filling: [0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1]

有效的Python代码:

def besthalf(d):
    s = sum(d)
    half = s // 2
    a = [1] + [0] * half
    for v in d:
        for j in range(half, v - 1, -1):
            if (a[j -v] == 1):
                a[j] = 1
    for j in range(half, 0, -1):
        if (a[j] == 1):
            m = j
            break
    return(s - 2 * m)

print(besthalf([1,5,6,11]))
print(besthalf([1,1,1,50]))
>>1
>>47

答案 1 :(得分:1)

 RestAssuredConfig config = RestAssuredConfig.config();
    config = config.encoderConfig(
        config.getEncoderConfig().defaultContentCharset("UTF-8")
            .defaultCharsetForContentType("UTF-8", "application/json"));
    config = config.decoderConfig(
        config.getDecoderConfig().defaultContentCharset("UTF-8")
            .defaultCharsetForContentType("UTF-8", "application/json"));

相同的Java代码

I'll convert this problem to subset sum problem
let's  take array int[] A = { 10,20,15,5,25,33 };
it should be divided into {25 20 10} and { 33 20 } and answer is 55-53=2

Notations : SUM == sum of whole array
            sum1 == sum of subset1
            sum2 == sum of subset1

step 1: get sum of whole array  SUM=108
step 2:  whichever way we divide our array into two part one thing will remain true
          sum1+ sum2= SUM
step 3: if our intention is to get minimum sum difference then 
sum1 and sum2 should be near SUM/2 (example sum1=54 and sum2=54 then diff=0 )

steon 4: let's try combinations


        sum1 = 54 AND sum2 = 54   (not possible to divide like this) 
        sum1 = 55 AND sum2 = 53   (possible and our solution, should break here)
        sum1 = 56 AND sum2 = 52  
        sum1 = 57 AND sum2 = 51 .......so on
        pseudo code
        SUM=Array.sum();
        sum1 = SUM/2;
        sum2 = SUM-sum1;
        while(true){
          if(subSetSuMProblem(A,sum1) && subSetSuMProblem(A,sum2){
           print "possible"
           break;
          }
         else{
          sum1++;
          sum2--;
         }
         }

答案 2 :(得分:0)

正在工作的C代码(如果有人感兴趣,但想法与@MBo所说的相同)

int someFunction(int n,int *arr)
{
    qsort (arr, n, sizeof(int), compare);
    int i,j;
    int dp[3000];

    for(j=0;j<3000;++j) dp[j] = 0;

    int sum = 0;
    for(i=0;i<n;++i) sum += arr[i];

    int sum2 = sum;

    if((sum&1) == 1) sum = sum/2+1;
    else sum = sum/2;

    dp[0] = 1;
    for(i=0;i<n;++i){
        for(j=sum;j>=arr[i];--j){
           if(dp[j-arr[i]] == 1){
               dp[j] = 1;
           }       
        }
     }

    for(i=sum;i>=1;--i){
        if(dp[i] == 1){
            return abs(sum2 - 2 * i);
        }
    }


    return 0;
}