【编程题目】输入两个整数 n 和 m,从数列 1,2,3.......n 中 随意取几个数, 使其和等于 m ... ★
第 21 题(数组)
2010 年中兴面试题
编程求解:
输入两个整数 n 和 m,从数列 1,2,3.......n 中 随意取几个数,
使其和等于 m ,要求将其中所有的可能组合列出来.
我的思路:
从小到大 依次拼凑 后面选的数字 必须比前面大 保证不重复
如: n = 4 m = 8
1 2 3 4 超过8 去掉最后一个数 导数第二个数加一
1 2 4 小于8 最后一个数等于 4 去掉最后一个数 导数第二个数加一
1 3 4 符合 输出 最后一个数等于 4 去掉最后一个数 导数第二个数加一
1 4 小于8 最后一个数等于 4 去掉最后一个数 导数第二个数加一
2 3 小于8
2 3 4 超过8 去掉最后一个数 导数第二个数加一
2 4 小于8 最后一个数等于 4 去掉最后一个数 导数第二个数加一
......
代码:
/* 第 21 题(数组) 2010 年中兴面试题 编程求解: 输入两个整数 n 和 m,从数列 1,2,3.......n 中 随意取几个数, 使其和等于 m ,要求将其中所有的可能组合列出来. start time = 15:55 end time = 17:03 */ #include <iostream> using namespace std; int FindCombine(int n, int m) { int method = 0; //一共有多少方法 if(m <= 0) { return 0; } else { int record[100]; //存储组合当前的取值 for(int i = 0; i < 100; i++) { record[i] = i + 1; } int num = 0; //组合中数字的个数 int sum = 0; //组合中数字加起来的和 while(sum < m) { sum += record[num]; num++; if(sum == m) { method++; printf("组合%d:", method); for(int i = 0; i < num; i++) { printf("%d ", record[i]); } printf("\n"); if(num == 1) { return method; } } if((sum >= m) || (sum < m && record[num - 1] == n && num >= 2)) //如果大小超过m 或者 最后一个数字大小等于n 更新record { num--; sum -= record[num]; num--; sum -= record[num]; if(record[num] <= n) { record[num]++; for(int i = 1; i <= n - record[num]; i++) { record[i + num] = record[num] + i; } } } else if(sum < m && record[num - 1] == n && num == 1) { return method; } } } } int main() { int w = FindCombine(50, 100); return 0; }
惯例上网找别人的方法, 一看我就郁闷了, 居然可以用动态规划, 我的算法算是白学了, 到用的时候一点都想不起来。
http://blog.sina.com.cn/s/blog_7571423b01016707.html 里有个详细的分析
http://www.cnblogs.com/freewater/archive/2012/07/16/2593218.html 里有非常精简的代码
vector<int> factors; void findFactor2(int sum,int n){ if(sum<0||n<0) return ; if(sum==0){ for(vector<int>::iterator iter=factors.begin();iter!=factors.end();++iter){ cout<<*iter<<' '; } cout<<endl; return; } factors.push_back(n);//典型的01背包问题 findFactor2(sum-n,n-1);//放n,n-1个数填满sum-n factors.pop_back(); findFactor2(sum,n-1);//不放n,n-1个数填满sum }