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

求满足x和≤A且y和≥B的点集子集的算法思路问询

思路解析:带约束的子集选择问题

嘿,这个问题本质是带约束的子集优化问题,暴力枚举所有子集显然只适用于n极小的场景,我给你梳理几个实用的思路,分情况讨论:

核心转化:先明确问题本质

我们可以把问题转化为更清晰的目标:在所有满足SUM(x) ≤ A的子集中,找到SUM(y)最大的那个。如果这个最大值≥B,说明存在符合要求的子集;反之则不存在。这个转化能帮我们把问题和经典算法挂钩。


分场景的解决方案

1. 当n较小(比如n≤20):折半枚举(Meet-in-the-Middle)

暴力枚举2^n个子集太恐怖,但把点分成两组(比如前n/2个和后n/2个),分别枚举每组所有子集的(sum_x, sum_y)对,复杂度就降到O(2^(n/2)),完全可行。

  • 步骤:
    • 拆分点集为两组S1、S2,枚举S1的所有子集,记录每个子集的sum_x和sum_y,把这些数据按sum_x排序。
    • 枚举S2的每个子集,计算当前的sum_x2和sum_y2,然后在S1的排序结果中用二分查找找到所有sum_x1 ≤ A - sum_x2的记录,取其中最大的sum_y1,那么当前子集的总sum_y = sum_y1 + sum_y2,记录全局最大值。
  • 注意:处理浮点数时,比较sum_x1 ≤ A - sum_x2要留精度余量(比如sum_x1 ≤ A - sum_x2 + 1e-9),避免浮点误差导致漏判。

2. 当x_i和A是有理数(可转化为整数):动态规划(背包DP)

有理数的话,我们可以把所有x值和A乘以一个最小公倍数,把它们转成整数,这样就变成经典的0-1背包问题:

  • 定义dp[t]表示x总和不超过t(转成整数后的t)时,能获得的最大y总和。
  • 初始化dp[0] = 0,其余为0或者负无穷。
  • 遍历每个点(x_i', y_i)(x_i'是转成整数后的x值),对t从转成整数后的A值倒序遍历到x_i',更新dp[t] = max(dp[t], dp[t - x_i'] + y_i)。
  • 最后看dp[A'](A'是转成整数后的A)是否≥B即可。
  • 注意:如果x的小数位数较多,要注意整数溢出问题,可以选择用高精度或者调整倍数(比如只保留足够的有效位数)。

3. 当n较大且需要精确解:分支定界法

如果n超过20但又需要精确解,分支定界是个不错的选择:

  • 先把点按y_i/x_i(单位x能获得的y值)从大到小排序,这样能优先探索更有潜力的分支。
  • 递归遍历每个点,分“选”和“不选”两种情况:
    • 选当前点:如果加上当前x后总和超过A,直接剪枝;否则更新当前sum_x和sum_y,继续递归。
    • 不选当前点:计算如果选剩下所有点能获得的最大y总和,如果这个值加上当前sum_y仍小于当前已知的最优sum_y,直接剪枝(没必要继续探索)。
  • 过程中记录全局最大的sum_y,最后判断是否≥B。

4. 近似解:贪心算法(适合不需要精确解的场景)

如果对结果的精度要求不高,可以用贪心快速得到一个近似解:

  • 把点按y_i/x_i从大到小排序(如果x_i=0,这类点优先选,因为不占x额度还能加y)。
  • 依次选点,直到加上下一个点的x后总和超过A为止。
  • 最后看sum_y是否≥B。
  • 注意:贪心不一定能得到最优解(比如可能存在一个x稍大但y极大的点,被前面几个小x点挤掉),但胜在速度快,适合大规模数据。

浮点数处理的关键细节

因为x_i和A是浮点数,一定要注意精度误差:

  • 比较sum_x ≤ A时,不要直接用sum_x <= A,而是用sum_x <= A + 1e-9(避免因为浮点精度丢失导致合法的sum_x被误判为超过A)。
  • 同理,判断sum_y ≥ B时,用sum_y >= B - 1e-9。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:02:37