【问题标题】:Algorithm to find combination of signs of integers in a set such that the set sums to 0寻找集合中整数符号组合的算法,使得集合总和为 0
【发布时间】:2021-06-15 20:51:33
【问题描述】:

给定 Sn 个正整数的集合,我们想知道是否可以找到一个组合S 中每个数字的符号数(+ 或 -),使得 S 的和为 0。

如何有效地解决这个问题?基于类似的问题,我想某种动态编程是有序的。有没有关于这个特定问题的文献(我找不到它)。

我猜这类似于子集和问题。但是,现在我们必须使用整个集合,并且对于每个整数 si 我们可以包含 -si+si,但不能同时使用。

【问题讨论】:

    标签: algorithm dynamic-programming complexity-theory np


    【解决方案1】:

    这个问题的解决方案涉及到子集和问题。

    如果有办法求和到数组总和的一半,那么我们可以将所有这些数字设置为负数。其余的数字将是正数。因为这些子集中的每一个的总和都是总和的一半,所以它们各自的总和将为 0。

    这是c++中的代码:

    #include<stdio.h>
    
    int arr[] = {1, 2, 2, 3, 4};
    int n = 5; // size of arr
    int sum = 0;
    
    // dp array only needs to be [n + 1][total sum + 1] big
    bool dp[30][100];
    inline void subset_sum(){
        for (int i = 0; i <= sum; i++)
            dp[0][i] = false;
    
        for (int i = 0; i <= n; i++)
            dp[i][0] = true;
    
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= sum; j++) {
                dp[i][j] = dp[i - 1][j];
                if (arr[i - 1] <= j)
                    dp[i][j] |= dp[i - 1][j - arr[i - 1]];
            }
        }
    }
    int main(){
        for (int i = 0; i < n; i++)
            sum += arr[i];
    
        // run subset sum dp using a bottom-up approach
        // True = sum is possible, False = not possible
        subset_sum();
    
        int max_half;
        for (int i = sum / 2; i>=1; i--){
            if (dp[n][i]){ // it is possible to sum to i using values in arr
                max_half = i;
                break;
            }
        }
    
        // output will be the closest sum of positives
        // and negatives to 0
        printf("%d\n", 2 * max_half - sum);
    
        return 0;
    }
    

    此代码的输出将是集合中正数和负数组合的最接近的可能总和为 0。

    2 * max_half - sum 可以从max_half - (sum - max_half) 推导出来,这将是我们最好的和减去其余数字。

    以下是不同数字集及其各自输出的一些示例:

    设置:{1, 2, 2, 3, 4},输出:0

    设置:{1, 1, 1, 1, 1},输出:-1

    设置:{5, 2, 6, 8, 9, 2},输出:0

    设置:{1, 50},输出:-49


    子集和问题网上有many explanations,这里就不解释了。

    这段代码的时间复杂度是O(n * sum),空间复杂度是O(n * sum)。

    通过使用一维 dp 数组,也可以牺牲一些时间复杂度来提高空间复杂度。

    【讨论】:

    • 这个想法是有道理的,但在尝试之后似乎有些不对劲。除了 dp[6] 超出范围(我猜应该是 dp[5] )之外,生成的 dp 数组是 [0, 4, 1, 3, 1, 2],这意味着不存在任何组合。但是,我们可以清楚地形成 1 + 2 - 2 + 3 - 4 的组合。知道发生了什么吗?
    • 看了一下,我选择使用的dp条件可能不是这种情况的最佳选择。这不仅仅取决于该值与 0 的接近程度。与此同时,我仍在尝试考虑更好的使用条件,或者可能是替代解决方案。
    • 我终于找到了解决这个问题的方法,并编辑了我的答案。请看一看。
    【解决方案2】:

    鉴于问题似乎是 NP 完全的, 使用 SAT、MILP、CP 或 ASP 求解器是最佳选择, 因为这些都是为解决这类问题而量身定制的。

    解决方案

    这是一个使用 ASP(答案集编程)的解决方案。

    给定一个文件instance.lp

    value(12).
    value(12).
    value(1).
    value(2).
    value(3).
    value(5).
    value(6).
    value(7).
    

    还有文件encoding.lp:

    % every value can be positive (or not)
    {pos(X)} :- value(X).
    
    % fail if the sum is not 0
    :- not 0 = #sum {V : pos(V); -V : not pos(V), value(V)}.
    
    % format output
    #show pos/1.
    #show neg(V) : not pos(V), value(V).
    

    问题可以使用clingo解决, potassco 工具集的 ASP 求解器(可通过 conda、pip、Ubuntu Package Manger 等轻松安装)。

    调用:

    clingo instance.lp encoding.lp
    

    给你结果:

    Answer: 1
    pos(1) pos(2) pos(3) pos(5) pos(7) neg(6) neg(12)
    

    您可以列举所有可能的解决方案:

    clingo instance.lp encoding.lp 0
    

    给你

    Answer: 1
    pos(1) pos(2) pos(3) pos(5) pos(7) neg(6) neg(12)
    Answer: 2
    pos(2) pos(3) pos(6) pos(7) neg(5) neg(1) neg(12)
    Answer: 3
    pos(5) pos(6) pos(7) neg(3) neg(2) neg(1) neg(12)
    Answer: 4
    pos(12) pos(1) pos(2) pos(3) neg(7) neg(6) neg(5)
    Answer: 5
    pos(12) pos(6) neg(7) neg(5) neg(3) neg(2) neg(1)
    Answer: 6
    pos(12) pos(1) pos(5) neg(7) neg(6) neg(3) neg(2)
    

    平均售价

    使用ASP解决问题的优势在于:

    • 易于维护(问题描述非常简短,易于阅读)
    • 非常快(基于 SAT 和 CDNL
    • 声明式(您只描述问题,而不是如何解决)
    • 可通过其他约束轻松扩展
    • 还能够进行各种优化(例如优化最大子集以形成总和)

    编辑 也可以复制粘贴两个文件的内容,自己在线查看结果,使用clingohere的js编译

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多