实现伪多项式DP子集总和

问题描述 投票:1回答:1

我尝试实现pseudo-polynomial time algorithm for subset sum在Wikipedia页面上提出的算法,我们的目标是确定是否存在{x_1,...,x_N}的非空子集,总和为零。因此,我们设置了一个范围,从负数之和(A)到正数之和(B),并创建一个矩阵来保存1≤i≤N和A≤s的值Q(i,s) ≤B。然后为了填充它,我们应该首先设置Q(1,s):=(x_1 == s),对于递归情况,我们设置Q(i,s):= Q(i − 1,s)或( xi == s)或Q(i-1,s-xi),对于A≤s≤B。

这是我的镜头,其中inp包含输入集。我会在变量arrindex中跟踪s的“真实”索引,因为s可能是负数,而我不能将矢量索引为负。

vector<vector<bool>> result (inp.size(), vector<bool>(abs(B-A)+1)); // initialize results matrix
for(int s = A,arrindex=0; s <= B; s++,arrindex++){
    if(s == inp[0])
        result[0][arrindex] = true;
for(int i = 1; i < inp.size(); i++){
    for(int s = A,arrindex=0; s <= B; s++,arrindex++){
        // CHECK: Q(i, s) := Q(i − 1, s) or (xi == s) or Q(i − 1, s − xi),  for A ≤ s ≤ B
        if(s == inp[i] || result[i-1][arrindex] || result[i-1][abs((s - inp[i])-A)])
            result[i][arrindex] = true;
    }
}

我的尝试给出了答案,但似乎常常是不正确的。举一个简单的例子,如果我的输入是{-2,1},答案应该是“否”,但是我得到的矩阵是

1 0 0 0
1 1 0 1

我认为哪一个表示“是”,对吗?所以我的问题是,我执行不正确吗?还是我的解释不正确?

c++ algorithm dynamic-programming subset-sum
1个回答
0
投票

我认为result[i - 1][abs((s - inp[i]) - A)]一词不正确。应该是:

A <= s - inp[i] && s - inp[i] <= B && result[i - 1][s - inp[i] - A]

您可以使用简单的lambda函数模仿矩阵来避免嵌套vector

const auto n_rows = inp.size();
const auto n_cols = static_cast<std::size_t>(B - A + 1);
auto q = [qm = std::vector<char>(n_rows * n_cols), n_rows, A]
         (auto i, auto j) mutable -> auto&
         { return qm[i + (j - A) * n_rows]; };

for (auto j = A; j <= B; ++j)
    q(0, j) = inp[0] == j;

for (std::size_t i = 1; i < n_rows; ++i)
    for (auto j = A; j <= B; ++j)
        if (inp[i] == j || q(i - 1, j) || (A <= j - inp[i] && j - inp[i] <= B && q(i - 1, j - inp[i])))
            q(i, j) = true;

const bool has_zero_subset = q(n_rows - 1, 0);
© www.soinside.com 2019 - 2024. All rights reserved.