一道编程题: 在1~n之间选择若干个数,使其和为m
这是一道很明显的动态规划的题目。
递推公式为
用sum(n, m)表示所有可能的1~n之间存在的和为m的组合
那么 sum(n,m) = sum(n-1, m) | sum(n-1, m-n)
直接上代码
void FindCombine(std::list<int> la, int n,int m) { if(m < 0 ) return ; if(m == 0) { for(std::list<int>::iterator iter = la.begin();iter!=la.end();iter ++) { std::cout<<*iter<<"+"; } cout << endl; return ; } if(n <= 0) { return ; } la.push_back(n); FindCombine(la,n-1,m-n); la.pop_back(); FindCombine(la,n-1,m); }
如果允许选择重复的数字呢?
递推公式为
sum(n,m) = sum(n-1, m) | sum(n, m-n)
只需要将上面的代码稍作修改
void FindCombine(std::list<int> &la, int n,int m) { if(n <= 0 || m <= 0) { return ; } if(n == m) { for(std::list<int>::iterator iter = la.begin();iter!=la.end();iter ++) { std::cout<<*iter<<"+"; } std::cout<<n<<std::endl; } la.push_back(n); FindCombine(la,n,m-n); la.pop_back(); FindCombine(la,n-1,m); }
还有另外一种解法
void FindCombine1(std::list<int> &la, int n,int m) { if(m < 0) { return ; } if(m == 0) { for(std::list<int>::iterator iter = la.begin();iter!=la.end();iter ++) { std::cout<<*iter<<"+"; } cout << endl; return ; } if(n <= 0) { return ; } for(int i = n; i>0 ;i--) { la.push_back(i); FindCombine1(la,i,m-i); la.pop_back(); } }