实现伪多项式DP子集和
Implementing Pseudopolynomial DP Subset Sum
我尝试实现维基百科页面上为子集和的伪多项式时间算法提出的算法,其中我们的目标是确定是否存在求和为零的{x_1,…,x_N}的非空子集。因此,我们设置了一个从负数之和(a(到正数之和(B(的范围,并创建一个矩阵来保持1≤i≤N和a≤s≤B的值Q(i,s(。然后,为了填充它,我们应该首先设置Q(1,s(:=(x_1==s(,对于递归情况,我们设置Q(i,s(:=Q(i−1,s
这是我的镜头,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
我认为这会表示"是",对吧?所以我的问题是,我是否错误地实现了这一点?还是我的解释不正确?
我认为术语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<bool>(n_rows * n_cols), n_rows, A]
(auto i, auto j) mutable
{ 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)
q(i, j) = (inp[i] == j || q(i - 1, j) ||
(A <= j - inp[i] && j - inp[i] <= B && q(i - 1, j - inp[i])));
const bool has_zero_subset = q(n_rows - 1, 0);
相关文章:
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- 在子集化后将包含索引号的列表列表映射到标准索引序列
- 显示字符串的集合和子集
- 如何使用 O(n) 中的 DP 计算预期匝数?
- 用于子集字符串的 Rcpp 函数
- 为什么我的子集和方法不正确?
- 从代码力解决 dp 问题 - 剪彩
- 计算总和为 x 的所有整数子集(包括负数)
- C++ LeetCode #377 的 DP 解决方案中,此代码是否有错误?
- 不带连续 1 的位字符串,使用自上而下的 DP
- 在尝试使用递归查找集合子集的总数时,我遇到了分割错误
- 从小于或等于某个 N 的数字列表中最小化或找到 n 个理想的子集和
- 使用 Rcpp 的高效矩阵子集
- C++没有 dp() 函数
- 返回给定 SEXP 的子集,而无需知道实际的内部数据类型
- 使用递归从子集和中查找最大和
- 如何获得比较两个向量对的子集
- 实现伪多项式DP子集和
- 现代编译器会优化只引用对象子集的局部变量吗
- 类方法子集的惰性评估