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