澄清答案...在SET

时间:2018-09-11 06:41:33

标签: algorithm dynamic-programming

我需要澄清此question的答案,但我无法发表评论(代表人数不足),所以我问一个新问题。希望没事。

问题是这样的:

  

给定一个数组,您必须找到最大可能的两个相等和,您   可以排除元素。

     

即1,2,3,4,6给定数组,我们可以得到最多两个等于6 + 2 =   4 + 3 + 1

     

即4,10,18,22,我们可以得到两个相等的总和,即18 + 4 = 22

     

除了暴力破解之外,您还能采用什么方法解决此问题   强制查找所有计算并检查两个可能的相等和?

     

edit 1:数组元素的最大数目为N <= 50,每个元素可以为   最高1 <= K <= 1000

     

编辑2:元素总数之和不能大于1000。

批准的答案如下:

  

我建议使用DP解决此问题,而不是跟踪A,B(   两组的大小),而是跟踪A + B,A-B(总和   两组的差异)。

     

然后针对数组中的每个元素,尝试将其添加到A,B或   都不是。

     

跟踪和/差的优点是您只需要   跟踪每个差异的单个值,即最大   您所看到的总和值的差异。

我不了解的是:

如果这是子集和的问题,我可以用DP来解决,其记忆矩阵为(N x P),其中N是集合的大小,P是目标和...

但是我无法弄清楚我应该如何跟踪A + B,A-B(如已批准答案的作者所说)。记忆矩阵的维数应该是多少?以及如何帮助解决问题?

答案的作者很友好,可以提供一个代码示例,但是由于我不了解python(我知道java),所以我很难理解。

2 个答案:

答案 0 :(得分:4)

我认为思考此解决方案与单个子集问题之间的关系可能会误导您。在这里,我们关心的是最大可实现的总和,此外,我们在遍历时需要区分两组不相交的数字。清楚地跟踪特定组合会太昂贵。

看看集合A和B之间的差异,我们可以说:

A - B = d
A = d + B

很显然,我们希望d = 0时的总和最高。我们怎么知道那笔款项?是(A + B) / 2

对于动态程序中的过渡,我们想知道将当前元素放置在A,B还是都不放置中是更好的选择。可以这样实现:

e <- current element
d <- difference between A and B

(1) add e to A -> d + e

why? 
A = d + B
(A + e) = d + e + B

(2) add e to B -> d - e

why? 
A = d + B
A = d - e + (B + e)

(3) don't use e -> that's simply
  what we already have stored for d

让我们看看Peter de Rivas的过渡代码:

# update a copy of our map, so
# we can reference previous values,
# while assigning new values
D2=D.copy()

# d is A - B
# s is A + B
for d,s in D.items():

  # a new sum that includes element a
  # we haven't decided if a 
  # will be in A or B
  s2 = s + a

  # d2 will take on each value here
  # in turn, once d - a (adding a to B),
  # and once d + a (adding a to A)
  for d2 in [d-a, d+a]:

    # The main transition:
    # the two new differences,
    # (d-a) and (d+a) as keys in
    # our map get the highest sum
    # seen so far, either (1) the
    # new sum, s2, or (2) what we
    # already stored (meaning `a`
    # will be excluded here)
    # so all three possibilities
    # are covered.
    D2[abs(d2)] = max(D2[abs(d2)], s2)

最后,我们存储了在d = 0时可见的最高A + B,其中A和B中的元素形成不交集。返回(A + B)/ 2。

答案 1 :(得分:1)

尝试此dp方法:它可以正常工作。

/*
 * 
 i/p ::

1
5
1 2 3 4 6
o/p : 8

1
4
4 10 18 22
o/p : 22


1
4
4 118 22 3
o/p : 0
 */
import java.util.Scanner;

public class TwoPipesOfMaxEqualLength {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- > 0) {
            int n = sc.nextInt();
            int[] arr = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                arr[i] = sc.nextInt();
            }
            MaxLength(arr, n);
        }
    }

    private static void MaxLength(int[] arr, int n) {

        int dp[][] = new int[1005][1005];
        int dp1[][] = new int[1005][1005];

        // initialize dp with values as 0.
        for (int i = 0; i <= 1000; i++) {
            for (int j = 0; j <= 1000; j++)
                dp[i][j] = 0;
        }

        // make (0,0) as 1.
        dp[0][0] = 1;


        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= 1000; j++) {
                for (int k = 0; k <= 1000; k++) {
                    if (j >= arr[i]) {
                        if (dp[j - arr[i]][k] == 1) {
                            dp1[j][k] = 1;## Heading ##
                        }
                    }
                    if (k >= arr[i]) {
                        if (dp[j][k - arr[i]] == 1) {
                            dp1[j][k] = 1;
                        }
                    }
                    if (dp[j][k] == 1) {
                        dp1[j][k] = 1;
                    }
                }
            }

            for (int j = 0; j <= 1000; j++) {
                for (int k = 0; k <= 1000; k++) {
                    dp[j][k] = dp1[j][k];
                    dp1[j][k] = 0;
                }
            }
        }

        int ans = 0;

        for (int i = 1; i <= 1000; i++) {
            if (dp[i][i] == 1) {
                ans = i;
            }
        }

        System.out.println(ans);

    }

}