【问题标题】:Algorithms - Dynamic programming - Subset sum of two arrays算法 - 动态规划 - 两个数组的子集和
【发布时间】:2015-12-16 19:24:50
【问题描述】:

我的作业包括一个动态编程问题:

给定两个自然整数数组(a1,a2,...,an 和 b1,b2,...,bn) 这样所有的都小于n^2,并且还给出了一个数字B 小于 n^3。

如果存在数组(c1,c2,...,cn),你需要判断:

对于每个 1

*此算法必须使用动态规划编写。

*另外,我们需要改变什么来准确地得到数组 c 给我们 Sum(c) = B

看待问题的另一种方式是说 c 等于 a 的子集,而它的补子集来自 b。

这是我为解决这个问题而编写的递归伪代码:

W(a,b,i, N)
    if i==-1
        if N==0     return true;
        else        return false;
    return W(a,b,i-1,N-a[i]) || W(a,b,i-1,N-b[i]);

T(n) = 2^n

在这里,要返回最佳路径,只需将其存储在树中,然后从(好的)端遍历到开始

我怎样才能用动态编程来写这个?这甚至会帮助运行时间吗?因为递归解具有独立的结果。

*我在谷歌上搜索了这个问题,除了“子集和问题”之外什么也没找到。

【问题讨论】:

  • 嗯,我认为您非常接近动态规划解决方案。只需要在递归方法中添加一个dp 表,就完成了。关于时间复杂度,在这种情况下,它将等于您的dp 表的大小。
  • 我不明白(逻辑上)表格表示如何在这里提供帮助。我们有 2^n 个调用,我最好将其表示为一棵树。它将如何运作?
  • 这是伪装的正常子集和。考虑一个新数组d[i] = a[i] - b[i] 和一个新数字g = n - sum(b)。解决subset-sum(d,g),你就有了原始问题的解决方案。
  • @Amit 您需要阅读有关动态编程的更多信息。基本上,dp 就像一个缓存层一样工作,每当您遇到之前计算的状态时,您会立即返回结果,而无需进行任何进一步的步骤/方法调用。因此,方法调用的数量受状态数量的限制。
  • @Amit你的理解不正确,比如从N = 10开始,a = {1,2,3}, b = {2,3,2}。经过两个步骤,您可以通过a3 + a2b3 + b2 两种方式从状态 (N = 10, 2) 移动到状态 (N = 5, 0)。所以,没有dp,你会重复调用函数(a, b, 0, 5)两次。

标签: algorithm subset subset-sum


【解决方案1】:

感谢@PhamTrung,我有一个解决方案:

设一个矩阵[B,n](最大尺寸[n^3,n])

示例:(n=3,B=8)

    0   1       2       3       4       ... 8
0   T   F       F       F       F       ... F
1   F   (1,1)   (1,2)   (1,3)   (1,4)   ... (1,8)
2   F   F       (2,2)   (2,3)   (2,4)   ... (2,8)
3   F   F       F       (3,3)   (3,4)   ... (3,8)

伪代码:

//Generate the matrix
A = new Array(n+1,B+1)
for(i: 0 to n) //run over lines
    for(j: 0 to B) //run over B columns
        if i==0 //if we are in the first row
            A[i,j] = j==0; //if this is [0,0], it is true. else, false
        else if i>j //if we have more numbers than the sum
            A[i,j] = false; //it cannot happen
        else
            //general case:
            //if we remove a[i] or b[i], will we get to a true statement?
            A[i,j] = (j-a[i] >= 0 && A[i-1, j-a[i]]) || (j-b[i] >= 0 && A[i-1, j-b[i]]);

is_set(n,B,A)
    if(A[n,B])
        return true;
    return false;

公式:

[0,j],j!=0 = F
[0,0]   = T
i > j   = F
i <= j  = (i-1, j - a[i]) || (i-1, j - b[i])

获取路线:

为了得到构建C的路线,我们还要在每个真点0(=a)或1(=b)中保存,从下往上遍历。

【讨论】:

  • @PhamTrung 谢谢,但可能是因为我没有太多的声誉,我可以在两天内将我的答案标记为已接受。
猜你喜欢
  • 2012-06-28
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 2013-11-27
相关资源
最近更新 更多