You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

伪多项式DP子集和算法实现错误排查咨询

伪多项式时间子集和算法实现错误排查

我帮你梳理了代码里的几个关键问题,这正是导致输入{-2,1}时结果错误的原因,咱们一步步来看:

核心错误点

1. 循环嵌套顺序完全颠倒

你把处理第i个元素的循环放在了初始化第一个元素的s循环里面,这会导致第一个元素的初始化还没完成,就开始处理后面的元素,整个矩阵的填充逻辑完全混乱。正确的顺序应该是:先初始化完第0行(对应第一个元素),再逐行处理每个后续元素,每行内遍历所有可能的和s。

2. 索引计算错误(越界+逻辑错误)

在计算s - inp[i]对应的数组索引时,你用了abs((s - inp[i])-A),这是错误的:

  • 当s - inp[i]小于A时,这个计算会把负的偏移量转成正数,导致访问完全不相关的数组位置。比如输入{-2,1}时,当i=1、s=-2,s - inp[i] = -3,A=-2,(s-inp[i])-A = -1,取abs后变成1,对应s=-1的位置,错误地用这个位置的值来判断,最终导致结果失真。
  • 正确的索引计算应该是(s - inp[i]) - A,但必须先判断(s - inp[i])是否在[A, B]范围内,否则会数组越界,访问非法内存。

3. 初始化逻辑的隐性问题

虽然vector<bool>默认会初始化为false,但显式初始化所有位置为false会让代码更清晰,避免后续调试混淆。

修正后的完整代码

#include <vector>
#include <iostream>
using namespace std;

bool hasZeroSubset(const vector<int>& inp) {
    if (inp.empty()) return false;

    // 计算范围A(负数总和)和B(正数总和)
    int A = 0, B = 0;
    for (int x : inp) {
        if (x < 0) A += x;
        else B += x;
    }

    int sumRangeSize = B - A + 1;
    // 初始化矩阵,所有位置默认false
    vector<vector<bool>> result(inp.size(), vector<bool>(sumRangeSize, false));

    // 初始化第0行:第一个元素对应的和
    for (int s = A, arrIndex = 0; s <= B; s++, arrIndex++) {
        result[0][arrIndex] = (s == inp[0]);
    }

    // 填充后续行
    for (int i = 1; i < inp.size(); i++) {
        for (int s = A, arrIndex = 0; s <= B; s++, arrIndex++) {
            // 三个条件:前i-1个元素已有和为s的子集,当前元素本身等于s,前i-1个元素有和为s-x_i的子集
            bool cond1 = result[i-1][arrIndex];
            bool cond2 = (s == inp[i]);
            bool cond3 = false;

            int targetSum = s - inp[i];
            // 先判断targetSum是否在合法范围内,避免越界
            if (targetSum >= A && targetSum <= B) {
                int targetIndex = targetSum - A;
                cond3 = result[i-1][targetIndex];
            }

            result[i][arrIndex] = cond1 || cond2 || cond3;
        }
    }

    // 查找和为0的位置:计算0对应的索引
    int zeroIndex = 0 - A;
    return result.back()[zeroIndex];
}

int main() {
    vector<int> test1 = {-2, 1};
    cout << (hasZeroSubset(test1) ? "存在符合条件的子集" : "不存在符合条件的子集") << endl;
    // 输出应为:不存在符合条件的子集
    return 0;
}

结果解读说明

对于你的测试用例{-2,1}:

  • A=-2(负数总和),B=1(正数总和),和的范围是-2到1,对应数组索引0到3。
  • 和为0对应的索引是0 - (-2) = 2。
  • 修正后的代码中,最后一行(处理完所有元素)的索引2位置是false,对应正确结论:不存在非空子集和为0。

另外要注意:这个算法的Q(i,s)本身就代表前i个元素中存在非空子集和为s,所以直接检查最后一行的0位置即可,不需要额外排除空集(空集的和为0,但我们的初始化和递归逻辑都只考虑非空子集)。

内容的提问来源于stack exchange,提问作者theupandup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:24:31