Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 子集和二维动态规划_C_Algorithm - Fatal编程技术网

C 子集和二维动态规划

C 子集和二维动态规划,c,algorithm,C,Algorithm,我试图找到一组n个数的子集,它们的和为m。例如,如果我有集合(10,20,30,40,40,50,80)和m=90,那么子集是(10,80),(20,30,40)和(40,50)。我有一些代码可以找到像这样的小案例,比如 M[i, j] = max(M[i − 1, j], M[i − 1, j − A[i]) 然后使用 if (M[n][m]!=0) { for ( i = n; i >= 1; i --) if (M[i - 1][j]!=M[i][j])

我试图找到一组n个数的子集,它们的和为m。例如,如果我有集合
(10,20,30,40,40,50,80)
m=90
,那么子集是
(10,80)
(20,30,40)
(40,50)
。我有一些代码可以找到像这样的小案例,比如

M[i, j] = max(M[i − 1, j], M[i − 1, j − A[i])
然后使用

if (M[n][m]!=0)
{
    for ( i = n; i >= 1; i --)
        if (M[i - 1][j]!=M[i][j])
        {
            printf ("Use item %d = %d\n", i, A[i]);
            j -= A[i];
        }
}
但是当我尝试更大的测试用例时,它不会返回所有的子集。非常感谢您的帮助。

/*首先,我们使用快速排序对M进行排序,例如,
/* first we sort M with a quicksort, for instance, 
   whose an efficient implementation can be easily found on the web. */
M = quicksort(M);

/* we don't consider elements greater than m 
   so we compute the index of the greatest element to consider */
int max = n - 1;
for (; max > 0 && M[max] > m; max--);

int total = 1 << (max + 1);
for (int i = 0; i < total; i++)
{
    /* In this loop we'll go through all the possible subsets of M */
    int sum = 0;
    for (int k=0; k<n; k++)
    {
        if ((1 << k) & i)
        {
             s += M[k]; 

             /* if s is greater than m no need to go further */
             if (s > m)
             {
                 break;
             }
        }
    }
    if (sum == m)
    {
        /* Here we have found a successful subset so 
           we can output it however we want.
           It is composed of all the elements used 
           to build s in the loop above */        
    }
}
它的高效实现可以在web上轻松找到*/ M=快速排序(M); 我们不认为元素大于M。 所以我们计算最大元素的索引来考虑*/ int max=n-1; 对于(;max>0&&M[max]>M;max--); int total=1
/*例如,首先我们使用快速排序对M进行排序,
它的高效实现可以在web上轻松找到*/
M=快速排序(M);
我们不认为元素大于M。
所以我们计算最大元素的索引来考虑*/
int max=n-1;
对于(;max>0&&M[max]>M;max--);

int-total=1所有的正数值都允许修剪,这大大降低了复杂性(但我不知道平均有多少)。对于大型集合,您可能需要更精确的算法,但如下所示:

  • 将(多)集合排序为一个数组,例如
    nums
    ;例如,nums={10,20,30,40,40,50,80}
  • 创建一个累积总和数组,
    cum
    ;那就是cum={10,30,60,100,140,190,270}
  • Now(C-ish伪码)

    void parts(目标、索引、集合){//假设我们只想打印集合
    如果(目标==0){
    打印装置;
    返回;
    }
    while(index>=0&&nums[index]>target)--index;//跳过过大的数字
    如果(index<0 | | cum[index]=0&&cum[index]>=target;--index){//当总和太小时,我们可以停止
    添加nums[index]进行设置;
    零件(目标-nums[索引],索引-1,集合);
    从集合中删除nums[索引];
    //如果不需要重复集,请跳过重复集,例如,
    //(40,50)将创建两次而不跳过:
    //而(index>0&&nums[index-1]==nums[index])——index;
    }
    }
    
    所有的正数都允许修剪,这大大降低了复杂性(但我不知道平均有多少)。对于大型集合,您可能需要更精确的算法,但如下所示:

  • 将(多)集合排序为一个数组,例如
    nums
    ;例如,nums={10,20,30,40,40,50,80}
  • 创建一个累积总和数组,
    cum
    ;那就是cum={10,30,60,100,140,190,270}
  • Now(C-ish伪码)

    void parts(目标、索引、集合){//假设我们只想打印集合
    如果(目标==0){
    打印装置;
    返回;
    }
    while(index>=0&&nums[index]>target)--index;//跳过过大的数字
    如果(index<0 | | cum[index]=0&&cum[index]>=target;--index){//当总和太小时,我们可以停止
    添加nums[index]进行设置;
    零件(目标-nums[索引],索引-1,集合);
    从集合中删除nums[索引];
    //如果不需要重复集,请跳过重复集,例如,
    //(40,50)将创建两次而不跳过:
    //而(index>0&&nums[index-1]==nums[index])——index;
    }
    }
    
    如果您不向我们展示您使用的代码,我们该如何帮助您?请不要显示项目中的所有代码,只显示相关的位。第一:这些数字都是正数(或者至少是非负数)?第二,你的例子包含40个两次,是打字错误还是允许多个元素?所有元素都是正数,允许多个元素。如果你不向我们展示你正在使用的代码,我们应该如何帮助你?请不要显示项目中的所有代码,只显示相关的位。第一:这些数字都是正数(或者至少是非负数)?第二,您的示例包含40个两次,是一个输入错误还是允许多个元素?所有元素都是正数,允许多个元素。如果我们循环遍历所有可能的子集,那么它就不是动态规划,正确吗?您可以编写一个更具动态性的解决方案:对于集合中的每个元素,您有两个选项W:它是否在成功的子集中。围绕这个想法,你可以建立一个递归的方法来考虑每一个新的元素,但是在最后,它仍然会遍历2个可能的子集,因为你想要所有和的相等的子集。m@PierrOz它通常不会遍历所有元素,因为您可以进行修剪(如果元素为非负)。在这个例子中,你不需要考虑任何包含80和50的子集(修剪2 ^(n-2)子集)等等。哦上帝,<代码> POW(2,N)< /代码>?为什么人们这么做?“我不明白为什么我们不考虑这个例子中的80和50?子集{10,80}和{50,40}符合条件。如果我们循环遍历所有可能的子集,那么它将不是动态规划,对吗?您可以编写一个更动态的解决方案:对于集合的每个元素,您有两个选项W:它是否在成功的子集中。围绕这个想法,你可以建立一个递归的方法来考虑每一个新的元素,但是在最后,它仍然会遍历2个可能的子集,因为你想要所有和的相等的子集。m@PierrOz它通常不会遍历所有元素,因为您可以进行修剪(如果元素为非负)。在这个例子中,你不需要考虑任何包含80和50的子集(修剪2 ^(n-2)子集)等等。哦上帝,<代码> POW(2,N)< /代码>?“人们为什么这样做?”丹尼尔菲什说
    void parts(target, index, set){  // assuming we only want to print the sets out
        if (target == 0){
            print out set;
            return;
        }
        while(index >= 0 && nums[index] > target) --index; // skip too large numbers
        if (index < 0 || cum[index] < target) return;  // done, all numbers too large or total too small
        for(; index >= 0 && cum[index] >= target; --index){  // we can stop when the total sum is too small
            add nums[index] to set;
            parts(target - nums[index], index-1, set);
            remove nums[index] from set;
            // if no duplicate sets are desired, skip duplicates, for the example,
            // (40,50) would be created twice without skipping:
            // while(index > 0 && nums[index-1] == nums[index]) --index;
        }
    }