Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.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++_Recursion_Subset Sum - Fatal编程技术网

C++ 递归:理解(子集和)包含/排除模式

C++ 递归:理解(子集和)包含/排除模式,c++,recursion,subset-sum,C++,Recursion,Subset Sum,我需要理解这个递归是如何工作的,我理解简单的递归示例,但更高级的示例很难。即使有两行代码我也有问题。。。返回语句本身。我只是对它的工作原理略知一二,尤其是and/or操作符。任何见解都是非常受欢迎的 bool subsetSumExists(Set<int> & set, int target) { if (set.isEmpty()) { return target == 0; } else { int

我需要理解这个递归是如何工作的,我理解简单的递归示例,但更高级的示例很难。即使有两行代码我也有问题。。。返回语句本身。我只是对它的工作原理略知一二,尤其是and/or操作符。任何见解都是非常受欢迎的

      bool subsetSumExists(Set<int> & set, int target) {
      if (set.isEmpty()) {
         return target == 0;
      } else {
         int element = set.first();
         Set<int> rest = set - element;
         return subsetSumExists(rest, target)
             || subsetSumExists(rest, target - element);
         } 
      }
||是逻辑或。它从左到右进行评估并短路

这意味着在表达式A | | B中,首先计算A。如果为真,则整个表达式为真,不进行进一步计算。如果A为false,则对B求值,表达式得到B的值


在您的示例中,A尝试在不使用集合中的第一个元素的情况下获得相同的和。B是使用集合中的第一个元素,它减少了剩余的总和,并尝试与元素的其余部分一起获得该值。

要理解递归,需要理解递归。 要做到这一点,你需要反复思考

在这种特殊情况下

对于任何:子集,目标

若集合为空且目标为0,则存在子集合

否则,请删除集合的第一个元素。使用步骤0检查是否存在subdetSumset、target或subdetSumset、target-removed_元素


集合减法看起来是一种奇怪的语法,但我假设它意味着元素上的pop

它通过寻找每一个可能的组合来工作,尽管它是指数型的

在| |语句中,LHS是包括当前元素的和,RHS是不包括当前元素的和。因此,在指数树下,每个元素的每一个组合都会被打开或关闭

顺便说一下,指数意味着如果你有30个元素,它将产生2到30的幂,即0x40000000或接近十亿个组合

当然,你的内存可能会用完


如果找到了解决方案,它可能不会在所有2^N情况下运行。如果没有解决方案,它将始终访问所有这些问题。

让我们先看看算法

基本情况,即当集合为空时,递归终止

否则,程序从集合中减去第一个元素

现在它将调用SubsetSumeExistsRest、target并检查其是否为真, 如果是,它将返回true,否则它将调用 subsetsumexistrest,target-element并返回它所返回的任何内容 返回

简单地说,只有当第一个子集subsetsumexistrest,target返回false时,它才会调用subsetsumexistrest,target-element

现在,让我们试着用一个小样本集{3,5}和一个8的和来运行这段代码。从现在起,我将调用函数sSE

sSE({3,5}, 8) => "sSE({5}, 8) || sSE({5},(8-3))"

sSE({5}, 8)   => sSE({}, 8) || sSE({}, (8-5)) 

sSE({}, 8)    => false.. now will call sSE({}, (8-5))

sSE({}, 3)    => false.. now will call sSE({5}, (8-3))

sSE({5}, 5)   => sSE({}, 5} || sSE({}, (5-5))

sSE({}, 5)    => false.. now will call sSE({}, (5-5))

sSE({}, 0)    => true.. ends here and return true

递归代码通常与归约概念结合在一起。一般来说,约简是通过某种转换将未知问题约简为已知问题的一种方法

让我们看看你的代码。您需要确定是否可以从输入数据集的元素构造给定的目标和。 如果数据集为空,则除了将目标和与0进行比较外,无需其他操作

否则,让我们应用减少。如果我们从集合中选择一个数字,实际上可能有两种可能性-所选数字参与您正在寻找的和,或者不参与。这里没有其他的可能性涵盖所有的可能性是非常重要的!。事实上,选择哪个数据元素并不重要,只要您能够覆盖剩余数据的所有可能性

第一种情况:数字不参与总和。我们可以将问题简化为一个较小的问题,数据集没有被检查的元素,目标和相同

第二种情况:数字参与总和。我们可以将问题简化为一个较小的问题,数据集不包含被检查的元素,请求的和减少了数字的值

请注意,此时您不知道这些情况是否属实。你只需继续减少它们,直到你得到一个微不足道的空案例,你可以肯定地知道答案


如果这两种情况中的任何一种都是真的,那么原始问题的答案将是真的。这正是运算符| |所做的-如果它的任何一个操作数(这两种情况的结果为真),它将产生真值。

如果我自己说的话,理解这个问题的困难源于| |运算符。让我们用另一种方式看一下相同代码的底部返回语句

if (subsetSumExists(rest, target - element))
        return true;
if (subsetSumExists(rest, target))
        return true;

return false;

因此,您在理解递归或布尔运算符和/或两者时遇到困难!例如,和/或如何选择返回哪一个?第一个还是第二个?+1为了理解递归,你需要理解递归!当我阅读理解递归时,我有一种似曾相识的感觉,你需要理解递归。