数组是否为“;总和和/或子项”;到'x`?

数组是否为“;总和和/或子项”;到'x`?,c,arrays,algorithm,performance,complexity-theory,C,Arrays,Algorithm,Performance,Complexity Theory,目标 我想写一个算法(在C中),它返回TRUE或FALSE(1或0),这取决于输入中给出的数组A是否可以“和/或分”到x(请参阅下文以了解更多信息)。请注意,A的所有值都是在[1,x-1]之间随机(均匀)采样的整数 澄清和示例 所谓“sum和/或sub”,我的意思是将“+”和“-”放在数组的每个元素前面并求和。让我们调用这个函数SumSub int SumSub (int* A,int x) { ... } SumSub({2,7,5},10) 应返回TRUE为7-2+5=10。您将注意到A

目标

我想写一个算法(在
C
中),它返回
TRUE
FALSE
1
0
),这取决于输入中给出的数组
A
是否可以“和/或分”到
x
(请参阅下文以了解更多信息)。请注意,
A
的所有值都是在[1,x-1]之间随机(均匀)采样的整数

澄清和示例

所谓“sum和/或sub”,我的意思是将“+”和“-”放在数组的每个元素前面并求和。让我们调用这个函数
SumSub

int SumSub (int* A,int x)
{
...
}

SumSub({2,7,5},10)
应返回
TRUE
为7-2+5=10。您将注意到
A
的第一个元素也可以被视为负数,因此
A
中元素的顺序无关紧要

SumSub({2,7,5,2},10)
应返回
FALSE
,因为无法对
array
的元素进行“和/或分”以达到
x
的值。请注意,这意味着必须使用
A
的所有元素

复杂性

n
A
的长度。如果要探索所有可能的正负组合,问题的复杂性是O(2^n)级。但是,某些组合比其他组合更可能出现,因此值得首先探索(希望输出结果是
真的
)。通常,需要从最大数中减去所有元素的组合是不可能的(因为
A
的所有元素都低于
x
)。另外,如果
n>x
,则尝试添加
A
的所有元素是没有意义的

问题


我应该如何编写这个函数?

不幸的是,你的问题可以简化为NP完全问题。因此,指数解是不可避免的

不幸的是,即使x被限制为0,这也是NP完全的,所以不要期望使用多项式时间算法。为了说明这一点,我将给出NP难的一个简单简化,它询问给定的多个正整数集是否可以划分为两个具有相等和的部分:


假设我们有一个由n个正整数B_1,…,B_n组成的划分问题的实例。在此基础上创建一个问题实例,其中A_i=B_i对于每个1原始问题的解决方案确实是如您所说的指数。但是,对于[]中的数字,在给定的范围[1,x-1]下,可以使解成为多项式。有一个非常简单的动态规划解决方案

命令如下:

时间复杂度:O(n^2*x)

内存复杂度:O(n^2*x)

其中,n=A[]中的元素数

为此,您需要使用动态规划方法

您知道可以在[-nx,nx]范围内进行的最小、最大范围。创建大小为(n)X(2*n*X+1)的二维数组。我们把这个称为dp[][]

dp[i][j]=从[0..i-1]中获取[]的所有元素是否可能使值j

所以

dp[10][3]=1表示取[]的前10个元素,我们可以创建值3

dp[10][3]=0表示取[]的前10个元素,我们无法创建值3

下面是一种用于此的伪代码:

int SumSub (int* A,int x)
{
    bool dp[][];//set all values of this array 0
    dp[0][0] = true;
    for(i=1;i<=n;i++) {
        int val = A[i-1];
        for(j=-n*x;j<=n*x;j++) {
            dp[i][j]=dp[ i-1 ][ j + val ] | dp[ i-1 ][ j - val ];
        }
    }
    return dp[n][x];
}
intsumsub(int*A,intx)
{
bool dp[][];//设置此数组的所有值0
dp[0][0]=真;

对于(i=1;i unds类似于一个典型的背包问题。数组的元素和大小有限制吗?我想使用尽可能大的数组(就CPU时间而言)。a
的元素限制在[1,x-1]之间如果代码中的所有值都可以在总和和/或子操作中使用。@ TrimoCt是的,必须使用所有的值,使得这个问题与数学问题不同,在这种情况下可以显示:(假装<代码>无符号< /代码>为简单的8位。)考虑<代码> SUMAST({ 250, 250, 5,5 } 254)。。这对于C是正确的,因为
无符号
溢出定义良好-只需添加4个元素。这在数学上是错误的,其范围是无限的。不确定OP想要什么,一个数学解决方案还是一个C解决方案。答案始终为“否”的问题也可以“简化为NP完全的子集和问题”​ (仅输出
{2,3},4
)​ 因此,对于Remi.b的问题来说,这种减少的存在并没有显示出任何硬度。​ ​ ​ ​