蓝桥杯 和为T dfs 二进制枚举

问题描述
  从一个大小为n的整数集中选取一些元素,使得它们的和等于给定的值T。每个元素限选一次,不能一个都不选。
输入格式
  第一行一个正整数n,表示整数集内元素的个数。
  第二行n个整数,用空格隔开。
  第三行一个整数T,表示要达到的和。
输出格式
  输出有若干行,每行输出一组解,即所选取的数字,按照输入中的顺序排列。
  若有多组解,优先输出不包含第n个整数的;若都包含或都不包含,优先输出不包含第n-1个整数的,依次类推。
  最后一行输出总方案数。
样例输入
5
-7 -3 -2 5 9
0
样例输出
-3 -2 5
-7 -2 9
2
数据规模和约定
  1<=n<=22
  T<=maxlongint
  集合中任意元素的和都不超过long的范围
又是基础题没有做出来。
参考自https://blog.csdn.net/S_999999/article/details/103390025
解法一dfs:假如我们从第一个数开始判断选还是不选然后往后搜索的话,也能做出来,不过不满足优先输出不包含后面的数的方案这个前提。所以我们从最后一个数开始往前搜索,并且在dfs内部,不选这个数的情况要在选这个数的代码上面。
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 vector<int> ans; //存储选了哪些数 
 4 int nums[30];  //存储输入的整数集
 5 int n, T;
 6 int cnt; //总方案数
 7 void dfs(int id, int sum) { //id表示当前遍历到的数的下标,sum表示当前已经选择的数的总和 
 8     if (id == -1) { //如果搜索完了 
 9         if (sum == T && ans.size() > 0) { //如果和为T且至少选了一个数 
10             for (int i = ans.size() - 1; i >= 0; i--) {  
11                 cout << ans[i] << " ";
12             }
13             cout << endl;
14             cnt++;
15         }
16         return; 
17     } 
18     dfs(id - 1, sum); //不选这个数 
19      
20     ans.push_back(nums[id]); //选这个数,把这个数加入到ans中 
21     dfs(id - 1, sum + nums[id]); //dfs下一层 
22     ans.pop_back(); //回溯 
23     
24 }
25 int main() {
26     cin >> n;
27     for (int i = 0; i < n; i++) {
28         cin >> nums[i];
29     }
30     cin >> T;
31     dfs(n - 1, 0); //从最后一个数开始往前搜索 
32     cout << cnt << endl;
33     return 0;
34 }

解法二:二进制枚举所有情况,参考自https://blog.csdn.net/z93478462/article/details/81193311

这一题可以用二进制枚举的思想。

比如从5个数字中选择几个的话,每个数字都有选或不选两种情况。

我们用数字0表示不选这个数,用数字1表示选这个数。

所以我们用一个5位数字的二进制01串,就可以表示出所有情况。

00000表示5个数字一个都不选,11111表示5个数字都选。

把题目给出的5个数字依次存入a[0], a[1], a[2], a[3], a[4]

比如以10011分析。我们从右往左看看当前这一位的数字是0还是1。

我们人为规定一下顺序。

10011&1 结果为1即题目给出的第一个数被选中 即是下标为0的数组元素被选中

10011&10 结果为1即题目给出的第二个数被选中  即是下标为1的数组元素被选中

10011&100 结果为0即题目给出的第三个数未被选中  即是下标为2的数组元素未被选中

10011&1000 结果为0即题目给出的第四个数未被选中  即是下标为3的数组元素未被选中

10011&10000 结果为1即题目给出的第五个数被选中  即是下标为4的数组元素被选中

这样顺序反一下,我们从00000到00001到00010到11111,就可以保证题目所要求的优先不选择位置靠后的元素。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int a[30];
 4 int main() {
 5     int n;
 6     cin >> n;
 7     for(int i = 0; i < n; i++) {
 8         cin >> a[i];
 9     }
10     int T;
11     cin >> T;
12     int ans = 0;
13     for (int i = 0; i < (1 << n); i++) { //从0~2^n-1个状态
14         int num = 0;
15         for (int j = 0; j < n; j++) { //遍历二进制的每一位
16             if (i & (1 << j)) { //判断二进制第j位是否存在
17                 num += a[j]; //如果存在加上第j个元素
18             }
19         }
20         if (num == T && i != 0) { //如果等于结果便将结果输出并将result加一 
21             for(int j = 0; j < n; j++) { 
22                 if (i & (1 << j)) { 
23                     cout << a[j] << " ";
24                 }
25             }
26             ans++;
27             cout << endl;
28         }
29     }
30     cout << ans << endl;
31     return 0;
32 }
原文地址:https://www.cnblogs.com/fx1998/p/12658092.html