问题描述
从一个大小为n的整数集中选取一些元素,使得它们的和等于给定的值T。每个元素限选一次,不能一个都不选。
输入格式
第一行一个正整数n,表示整数集内元素的个数。
第二行n个整数,用空格隔开。
第三行一个整数T,表示要达到的和。
第二行n个整数,用空格隔开。
第三行一个整数T,表示要达到的和。
输出格式
输出有若干行,每行输出一组解,即所选取的数字,按照输入中的顺序排列。
若有多组解,优先输出不包含第n个整数的;若都包含或都不包含,优先输出不包含第n-1个整数的,依次类推。
最后一行输出总方案数。
若有多组解,优先输出不包含第n个整数的;若都包含或都不包含,优先输出不包含第n-1个整数的,依次类推。
最后一行输出总方案数。
样例输入
5
-7 -3 -2 5 9
0
-7 -3 -2 5 9
0
样例输出
-3 -2 5
-7 -2 9
2
-7 -2 9
2
数据规模和约定
1<=n<=22
T<=maxlongint
集合中任意元素的和都不超过long的范围
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 }