Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.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++ - Fatal编程技术网

C++ 函数检查向量中的任何数字组合是否相加为整数?

C++ 函数检查向量中的任何数字组合是否相加为整数?,c++,C++,首先,我想找一些简单易懂的东西,而不是最有效的 我正在尝试创建一个函数,该函数将接受一个向量和一个int。如果向量中的任何数字加起来等于int,则函数应返回true 向量将以其中的数字1,2,3,4,5,6,7,8,9,10开始,整个程序中的数字将被删除。不会有重复的数字 int可以是2到12之间的任意数字 一些例子: vector={2,3,4,5}int=7函数返回true,因为3+4=7 vector={1,5,8}int=7函数返回false,因为这些数字都不能相加到7 vector=

首先,我想找一些简单易懂的东西,而不是最有效的

我正在尝试创建一个函数,该函数将接受一个
向量和一个
int
。如果向量中的任何数字加起来等于int,则函数应返回
true

向量将以其中的数字
1,2,3,4,5,6,7,8,9,10开始,整个程序中的数字将被删除。不会有重复的数字

int
可以是2到12之间的任意数字

一些例子:

  • vector={2,3,4,5}int=7
    函数返回
    true
    ,因为
    3+4=7
  • vector={1,5,8}int=7
    函数返回
    false
    ,因为这些数字都不能相加到7
  • vector={3,6}int=3
    函数返回
    true
    ,因为
    3=3
  • vector={5}int=2
    函数返回
    false
    ,因为五不能相加为二
这是我完成游戏所需的最后一个函数。我觉得我错过了一个简单的解决方案,但我不确定。有人能告诉我怎么做,或者给我指出如何解决这个问题的正确方向吗?提前谢谢您。

这不是一个问题吗


另请参见:

您需要做的是找到所有可能的组合,然后检查其中是否有正确的总和。双递归函数可以进行检查

bool canFormSum(vector<int>::iterator rest, vector<int>::iterator end, 
  int sumSoFar, int targetSum)
{
  if(rest == end) return false;
  if(sumSoFar + *rest == targetSum) return true;
  if(canFormSum(rest + 1, end, sumSoFar, targetSum)) return true;
  if(sumSoFar + *rest > targetSum) return false;
  return canFormSum(rest + 1, end, sumSoFar + *rest, targetSum);
}
bool canFormSum(向量::迭代器rest,向量::迭代器end,
内部sumSoFar,内部targetSum)
{
如果(rest==end)返回false;
if(sumSoFar+*rest==targetSum)返回true;
if(canFormSum(rest+1,end,sumSoFar,targetSum))返回true;
if(sumSoFar+*rest>targetSum)返回false;
返回canFormSum(rest+1,end,sumSoFar+*rest,targetSum);
}
这是递归计算的一个很好的例子,但对于小向量以外的任何东西,它的性能都很糟糕。

对于一般情况(向量大小>10)

f({a,b,c,d,…},e)
是集合
{a,b,c,d,…}
中的任何数字是否等于
e
的结果

注意,如果
e=x+y+z+…
,则(1)
a
{x,y,z,…}
集合中,或者(2)
a
不在
{x,y,z,…}
集合中。这意味着,我们有递归定义:

f({a, etc...}, e) = f({etc...}, e-a) || f({etc...}, e)
显然,如果总和为0,则关系始终为真,不包括集合中的任何元素:

f({...}, 0) = true
如果集合为空且总和不为零,则关系始终为假:

f({}, e) = false (if e != 0)
这些是递归的基本情况



编辑:进一步讨论请参见。

您必须尝试所有可能的组合,直到找到解决方案。这样的问题对语言“prolog”是有好处的。所以我们必须模拟回溯。 这段代码在c的末尾

#include<stdio.h>

int check (int* in, int sum) {
  while (1) {
    int act = *in++;
    if (act == 0) return 0;
    int rest = sum - act;
    if (rest > 0) {   // test in the order of expected likelyhoods
      if (1 == check (in, rest)) return 1;     // found
    }
//  if (rest < 0) return 0; // minor optimization, valid if list is ordered ascendant
    if (rest == 0) return 1;  // found;
  }
//return -1; // only necessary on poor compilers
}

void pr (int* in, int sum) {
    int res = check (in, sum);

    while (*in) {
      printf ("%d ", *in ++);
    }
    if (res == 0) {
        printf(" != %d\n", sum);
    } else {
        printf(" == %d\n", sum);
    }
}

int main () {

    int p1[] = {2,3,4,5, 0};
    pr (p1, 7);

    int p2[] = {1,5,8, 0};
    pr (p2, 7);

    int p3[] = {3,6, 0};
    pr (p3, 3);

    int p4[] = {5, 0};
    pr (p4, 2);

    int p5[] = {1, 100, 6, 0};
    pr (p5, 7);

    return 0;

}

考虑到注释中的附加信息,以下函数应该可以(我假设同一个数字不能在总和中使用两次):

typedef std::vector::iterator iter;
布尔包含求和(iter开始、iter结束、整数和)
{
while(开始!=结束)
{
--结束;
如果(*结束>总和)
继续;
if(包含_和(开始、结束、和-*结束))
返回true;
}
返回和==0;
}
只是比较一下我的(C)解决方案和celtschk(C++)解决方案。(基本上比较的是方法,而不是语言)

意味着将近2.7亿次递归方法调用

现在我的方法

#include<stdio.h>
#include<stdlib.h>

int counter;

int check (int* in, int sum) {
  counter ++;
  while (1) {
    int act = *in++;
    if (act == 0) return 0;
    int rest = sum - act;
    if (rest == 0) return 1;  // found;
    if (rest > 0) {
      if (1 == check (in, rest)) return 1;     // found
    }
  }
  return -1;
}

void pr (int* in, int sum) {
    counter = 0;
    int res = check (in, sum);

    while (*in) {
      printf ("%d ", *in ++);
    }
    if (res == 0) {
        printf(" != %d %d\n", sum, counter);
    } else {
        printf(" == %d %d\n", sum, counter);
    }
}

int main () {
    int p0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
                11,12,13,14,15,16,17,18,19,20,
                21,22,23,24,25,26,27,28,29,30,
                0};
    pr (p0, 77);    

    int p1[] = {2,3,4,5, 0};
    pr (p1, 7);

    int p2[] = {1,5,8, 0};
    pr (p2, 7);

    int p3[] = {3,6, 0};
    pr (p3, 3);

    int p4[] = {5, 0};
    pr (p4, 2);

    int p5[] = {1, 100, 6, 0};
    pr (p5, 7);

    return 0;

}    
Ups,只需22次迭代!

任何人都可以决定用哪种方法来考虑更“优雅”

你的向量是否包含负数?你知道向量中的所有数字是否都是唯一的?如果你有重复的,问题就更难了。它们都是唯一的,唯一可能的数字是1-10。谢谢你的回复!在第一个例子中,2+5也等于7。一旦它找到一个组合,加起来就是你想要的,它会短路吗?3+6=3是怎么回事?您需要更好地定义您的规则。元素的顺序是否与示例中的相同?是的,但这是一条注释,而不是编写时的答案。当然,是递归。但你的解决方案是什么?还是你告诉我们,会有解决办法?数学家?@stefanbachert:做你自己的家庭作业☺. 这仅仅是10行代码。(不考虑动态规划混乱,因为OP并不以效率为目标。)这种方法也适用于重复的数字。而且顺序也不在乎,*在++中,没有parens和space就不好,正如我说的:prooven不运行:1100 6!=7以一种更具建设性的方式,你知道一种证明或反驳递归函数正确性的正式方法吗?我认为celtschk更优雅,尽管“你必须找到所有可能的组合”不,你不必。@piotr:如果这个函数给出了错误的答案,你能给出有效的测试数据吗?我似乎找不到这样的测试用例。我也没有发现逻辑上有任何问题。我检查了一下,似乎它是有效的。我道歉。一旦我的投票被解锁,我将立即投票。@stefanbachert:不,没有。请注意,
end
在进行递归调用之前是递减的。但是,仍然可以进行优化,因为数字保证为正:如果
*end
大于
sum
,我们已经知道它不能是sum的一部分,因此在这种情况下不需要递归调用(并不是说它会对最多10个值产生明显的差异)。我将在中编辑这一改进。如果序列为空,那么算法显然是正确的。如果序列不是空的,则有两种情况:要么有一个集合包含给出和的最后一个元素,要么没有。有suc
typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
  while (begin != end)
  {
    --end;
    if (*end > sum)
      continue;
    if (contains_sum(begin, end, sum - *end))
      return true;
  }
  return sum == 0;
}
#include <iostream>
#include <vector>
using namespace std;

int counter = 0;

typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
  counter ++;
  while (begin != end)
  {
    --end;
    if (contains_sum(begin, end, sum - *end))
      return true;
  }
  return sum == 0;
}


int main () {
    vector<int> data;
    for (int i = 1; i <= 30; i ++) {
        data.push_back(i);
    }
    int target = 77;

    if (contains_sum (data.begin(), data.end(), target)) {
      cout << "possible\n" << counter;
    } else {
      cout << "not possible\n << counter";
    }

}
possible
268304387
#include<stdio.h>
#include<stdlib.h>

int counter;

int check (int* in, int sum) {
  counter ++;
  while (1) {
    int act = *in++;
    if (act == 0) return 0;
    int rest = sum - act;
    if (rest == 0) return 1;  // found;
    if (rest > 0) {
      if (1 == check (in, rest)) return 1;     // found
    }
  }
  return -1;
}

void pr (int* in, int sum) {
    counter = 0;
    int res = check (in, sum);

    while (*in) {
      printf ("%d ", *in ++);
    }
    if (res == 0) {
        printf(" != %d %d\n", sum, counter);
    } else {
        printf(" == %d %d\n", sum, counter);
    }
}

int main () {
    int p0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
                11,12,13,14,15,16,17,18,19,20,
                21,22,23,24,25,26,27,28,29,30,
                0};
    pr (p0, 77);    

    int p1[] = {2,3,4,5, 0};
    pr (p1, 7);

    int p2[] = {1,5,8, 0};
    pr (p2, 7);

    int p3[] = {3,6, 0};
    pr (p3, 3);

    int p4[] = {5, 0};
    pr (p4, 2);

    int p5[] = {1, 100, 6, 0};
    pr (p5, 7);

    return 0;

}    
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
 20 21 22 23 24 25 26 27 28 29 30  == 77 22
2 3 4 5  == 7 4
1 5 8  != 7 4
3 6  == 3 1
5  != 2 1
1 100 6  == 7 2