c或c+中为负值的子集和+;

c或c+中为负值的子集和+;,c,algorithm,subset-sum,C,Algorithm,Subset Sum,我有这段代码用于查找正值的子集和,我搜索的每一个地方都只看到正整数或高级java编写的程序。我想知道如何实现我的C程序可以处理负数。实际上,我想让它找到0的和。我有个主意 取集合中的最小值,称之为k 通过绝对值k添加集合中的每个元素 按绝对值k加和 执行算法 但我发现这是行不通的。取集合(-5,10),看看是否有子集加起来等于5。我们将转换(-5,10)->(0,15)和5->10-5+10=5,但0+15!=十, 我在网上搜索了很多想法,但找不到答案 #include <stdio.

我有这段代码用于查找正值的子集和,我搜索的每一个地方都只看到正整数或高级java编写的程序。我想知道如何实现我的C程序可以处理负数。实际上,我想让它找到0的和。我有个主意

  • 取集合中的最小值,称之为
    k
  • 通过绝对值
    k
    添加集合中的每个元素
  • 按绝对值
    k
    加和
  • 执行算法

  • 但我发现这是行不通的。取集合(-5,10),看看是否有子集加起来等于5。我们将转换(-5,10)->(0,15)和5->10-5+10=5,但0+15!=十,


    我在网上搜索了很多想法,但找不到答案

    #include <stdio.h>
    
    typedef int bool;
    #define true 1
    #define false 0
    
    bool isSubsetSum(int set[], int n, int sum) {
        // Base Cases
        if (sum == 0)
            return true;
        if (n == 0 && sum != 0)
            return false;
    
        if (set[n - 1] > sum)
            return isSubsetSum(set, n - 1, sum);
    
        return isSubsetSum(set, n - 1, sum) ||
               isSubsetSum(set, n - 1, sum - set[n - 1]);
    }
    
    int main() {
        int set[] = { -3, 34, -2, 12, 5, 8 };
        int sum = 0;
        int i;
        int n = sizeof(set) / sizeof(set[0]);
        if (isSubsetSum(set, n, sum) == true)
            printf("Found a subset");
        else
            printf("No subset");
        return 0;
    }
    
    #包括
    typedef int bool;
    #定义真1
    #定义false 0
    bool isSubsetSum(整数集[],整数n,整数和){
    //基本情况
    如果(总和=0)
    返回true;
    如果(n==0&&sum!=0)
    返回false;
    如果(设置[n-1]>总和)
    返回isSubsetSum(集合,n-1,sum);
    返回isSubsetSum(集合,n-1,总和)||
    isSubsetSum(集合,n-1,和集合[n-1]);
    }
    int main(){
    int set[]={-3,34,-2,12,5,8};
    整数和=0;
    int i;
    int n=sizeof(set)/sizeof(set[0]);
    if(isSubsetSum(设置,n,和)=真)
    printf(“找到子集”);
    其他的
    printf(“无子集”);
    返回0;
    }
    
    我想您可以通过删除溢出测试来尝试暴力尝试:

    #include <stdio.h>
    
    int isSubsetSum(int set[], int n, int sum, int empty_ok) {
        // Base Cases
        if (sum == 0 && empty_ok)
            return 1;
    
        if (n == 0)
            return 0;
    
        return isSubsetSum(set, n - 1, sum, empty_ok) ||
               isSubsetSum(set, n - 1, sum - set[n - 1], 1);
    }
    
    int main(void) {
        int set[] = { 3, 34, 2, 12, 5, 8 };
        int n = sizeof(set) / sizeof(set[0]);
        int sum = 6;
    
        if (isSubsetSum(set, n, sum, 0) == true)
            printf("Found a subset");
        else
            printf("No subset");
        return 0;
    }
    
    #包括
    int isSubsetSum(int set[],int n,int sum,int empty_ok){
    //基本情况
    如果(总和=0&&empty\u确定)
    返回1;
    如果(n==0)
    返回0;
    返回isSubsetSum(设置,n-1,求和,空\u确定)||
    isSubsetSum(集合,n-1,和集合[n-1],1);
    }
    内部主(空){
    int set[]={3,34,2,12,5,8};
    int n=sizeof(set)/sizeof(set[0]);
    整数和=6;
    if(isSubsetSum(设置,n,求和,0)=真)
    printf(“找到子集”);
    其他的
    printf(“无子集”);
    返回0;
    }
    
    不幸的是,这个解决方案的时间复杂度是O(2n)

    以下是针对最多64个元素的设置的非递归解决方案:

    int isSubsetSum(int set[], int n, int sum) {
        unsigned long long last;
    
        if (n == 0)
            return sum == 0;
    
        last = ((1ULL << (n - 1)) << 1) - 1;
    
        // only find non empty subsets for a 0 sum
        for (unsigned long long bits = 1;; bits++) {
             int s = 0;
             for (int i = 0; i < n; i++) {
                 s += set[i] * ((bits >> i) & 1);
             }
             if (s == sum)
                 return 1;
             if (bits == last)
                 return 0;
        }
    }
    
    int isSubsetSum(int set[],int n,int sum){
    未签名的长最后;
    如果(n==0)
    返回和==0;
    最后=((1全部i)和1);
    }
    如果(s==总和)
    返回1;
    如果(位==最后一位)
    返回0;
    }
    }
    

    说明:类型
    无符号long
    保证至少有64个值位<代码>位从
    1
    最后一个
    不等,并将
    n
    位的所有可能位模式都取下,但全部关闭除外。对于
    位的每个值
    ,我对设置了相应位的元素求和,因此测试所有可能的非空子集。

    我真的不理解您的策略。您不应该使用绝对值。
    a+b
    的和与
    |a |+b |
    的和几乎没有关系(好吧,有一些关系,但是如果你在某处使用它们,那么我就错过了;)

    如果您有一种算法,可以在正整数中找到一个子集,这些正整数加起来等于
    x
    ,那么您也可以将其用于负数。它不会那么有效,但只要有一个小技巧,它就可以工作

    首先,向所有数字添加一个偏移量,使它们都为正。现在,您将查找总计为
    x+y*offset
    的子集,其中
    y
    是子集的大小。你有

    A = -1, -3, -2, 6 12, 48
    
    您正在寻找一个子集,其总和为
    0
    ,然后首先将3添加到所有数字中

    b = 2, 0, 1, 9, 15, 51
    
    然后试着找到一个子集大小
    1
    加起来就是
    3
    ,一个子集大小
    2
    加起来就是
    6
    ,一个子集大小
    4
    ,加起来就是
    12
    ,这就是

    12 = 2+0+1+9    ie    0 = -1 + -3 + -2 + 6
    
    这样做不是很有效,因为您必须应用算法
    N
    -次(
    N
    =输入大小)。但是,如果您的正数算法允许您修正子集的大小,这可能会补偿效率上的损失。

    代码有TBD错误

    但OP要求它留下来。我以后再修或者明天取下来


    OP的代码有问题,因为它正在搜索错误的

    通过找到最小值并对
    集合[]
    的每个元素进行偏移,问题变成了唯一的正数之一——显然OP之前已经解决了这个问题

    诀窍是目标
    sum
    需要用
    n*offset

    #include <stdio.h>
    #include <stdbool.h>
    //typedef int bool;
    //#define true 1
    //#define false 0
    
    bool isSubsetSum(int set[], int n, int sum, int offset) {
        // Base Cases
        if ((sum  + n*offset) == 0)
            return true;
        if (n == 0 && (sum  + n*offset) != 0)
            return false;
    
        if (set[n - 1] > sum + n*offset)
            return isSubsetSum(set, n - 1, sum, offset);
    
        return isSubsetSum(set, n - 1, sum, offset) ||
               isSubsetSum(set, n - 1, sum - set[n - 1], offset);
    }
    
    int main() {
        int set[] = { -3, 34, -2, 12, 5, 8 };
        int sum = 0;
        int i;
        int n = sizeof(set) / sizeof(set[0]);
        int min = -3;  // TBD code to find minimum
        for (i = 0; i<6; i++) set[i] -= min;
    
        if (isSubsetSum(set, n, sum, -min) == true)
            printf("Found a subset");
        else
            printf("No subset");
        return 0;
    }
    

    typedef int bool#定义真1定义假0 <代码>好上帝,不,选一种语言,请高兴。这不是C++!但我发现这是行不通的。这不是一个有用的问题描述。你到底是指C和C++中的负值子集和?TBH,我真的不明白你想做什么,但是,如果你有一个适用于正整数的alogrithm,你可以简单地添加一个偏移量,使所有数字都为正,然后通过查找大小为1的子集加起来等于x+偏移量,大小为2的子集加起来等于x+偏移量*2,等等,来应用该算法。。。,其中x是你要找的实际和,我知道,但也许这可以通过递归得到?尽管如此,还是要感谢这个例子。我的主要问题是,必须使用sum=0。但是,始终显示如果sum=0,则会找到十个子集。@AdomasArabella:这是一个最多64个元素的非递归解决方案。子集可以为空。我的程序的目的是寻找空和。我的意思是,集合{1,-3,-2,612,48}我必须找到一个子集和,它是0-1+-3+-2+6=0。类型
    无符号长
    保证至少有64个值位<代码>位
    1
    last
    不等,包含所有
    n
    位的可能位模式。对于
    Found a subset