一维数组任意几个元素之和等于某个值的问题【递归】

文章讲述了如何使用递归方法解决一维数组中任意元素之和等于给定值的问题,通过反证法和逻辑闭环进行分析,强调了避免陷入证明细节的重要性。作者还给出了C++代码实现。
摘要由CSDN通过智能技术生成

又一个让我觉得自己蠢笨的题目,这些天一直在学习从另一个视角看问题。应该会慢慢变得灵活变通吧

题目:已知一个一维数组a1…n,又已知一整数m。如能使数组a中任意几个元素之和等于m,则输出YES,否则则输出NO。

【思考分割线------------------------------------------------------------------------】
如果不是因为在递归栏目看到这题,大概是要把我难死。又是任意,又是数组,随机取数的可能性多到不胜枚举。怎么设计都不在我可以用循环和选择可以解决的。但他在递归,其实即使在递归我也难住了。因为没想到怎么递归,笑拥咧。】
【-----------------------------------------------------------】
这题的思考方式很有意思:反证法。
如果任意个数的元素之和等于m,那么这个任意就可以进行以下分类:
①末尾元素正好等于m
②末尾元素不等于m,而前面的n-1个元素中有某个元素等于m
③两个或以上元素之和为m,这种情况下,有可能取到末尾元素或者取不到,因此只要:

  • 在取到末尾元素的时候证明前n-1个元素中存在任意几个之和等于 m - a[n] 即可。
  • 取不到的时候就是证明前n-1个元素中存在任意几个之和等于 m ,也就是前 n-2 个元素中有元素之和为 m - a[n - 1]。

如此一来,就可以将逻辑进行一个闭环然后进行递归即——看a[n]是否取到或者等于m,再看前n-1个元素中的末尾元素是否取到或等于m,此时依旧可以看a[n-1]是否等于m;在取到末尾元素时证明前 n-1 元素中有元素之和为m - a[n],取不到时证明前 n - 2 个元素中有元素之和为m - a[n - 1]、m - a[n - 2]以此类推……

个人觉得我们经常陷入的一个思维陷阱就是希望证明出某个问题的解决细节,最好是能够搞清楚为什么这么做,比如大家都知道1+1=2,但是陷入证明陷阱之后就会想问,为什么1+1=2?凭什么??实际上我们只要使用1+1=2这个已知的东西到更复杂的问题中去就行。
所以这里的递归内部是如何运行,可以不做纠结,否则会越来越糊涂。

采用全局变量编写程序如下:

#include<iostream>
using namespace std;
const int Max1 = 51;
int a[Max1],n,m;
bool flag;
void sum(int,int);

int main(){
  cin>>n;
  cin>>m;
  for(int i = 1;i<=n;i++)
    cin>>a[i];
  flag = false;
  sum(n,m);
  if(flag) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
}
void sum(int n,int m){
  if(a[n]==m) flag = true;
  else if(n == 1) return;//递推到第一个元素后仍然没有满足条件的,结束
  else{
         sum(n-1,m-a[n]);//判断前n-1个元素中是否有元素之和为m- a[n]
         sum(n-1,m);//判断前n-1个元素中是否有元素之和为m
  }
}

好的,这是一个关于递归算法问题。根据您的要求,我可以给您提供一个C++递归算法实现,如下所示: ```c++ #include <iostream> using namespace std; bool isSubsetSum(int arr[], int n, int sum) { // 如果 sum 为 0,则说明已经找到了和为 m 的子集,返回 true。 if (sum == 0) return true; // 如果 n 为 0,但 sum 不为 0,则说明已经遍历完了数组元素,但仍然没有找到和为 m 的子集,返回 false。 if (n == 0 && sum != 0) return false; // 如果 arr[n-1] 大于 sum,则不包括 arr[n-1],递归处理前 n-1 个元素。 if (arr[n-1] > sum) return isSubsetSum(arr, n-1, sum); // 返回 isSubsetSum 的两个可能结果:包含 arr[n-1] 或不包含 arr[n-1]。 return isSubsetSum(arr, n-1, sum) || isSubsetSum(arr, n-1, sum-arr[n-1]); } int main() { int n, arr[25], m; cin >> n; for (int i = 0; i < n; i++) cin >> arr[i]; cin >> m; // 调用 isSubsetSum 函数,并输出结果。 if (isSubsetSum(arr, n, m)) cout << "YES" << endl; else cout << "NO" << endl; return 0; } ``` 该算法使用了递归的思想,通过不断缩小数组范围,判断数组是否存在和为m的子集。具体实现过程如下: - 如果 sum 为 0,则说明已经找到了和为 m 的子集,返回 true。 - 如果 n 为 0,但 sum 不为 0,则说明已经遍历完了数组元素,但仍然没有找到和为 m 的子集,返回 false。 - 如果 arr[n-1] 大于 sum,则不包括 arr[n-1],递归处理前 n-1 个元素。 - 返回 isSubsetSum 的两个可能结果:包含 arr[n-1] 或不包含 arr[n-1]。 希望这个算法对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值