算法练习:排列组合之组合和

来源:互联网 发布:网络延时1000 编辑:程序博客网 时间:2024/05/20 01:38

问题描述

给出一组不同的正整数序列和一个目标值,求出所有可能的组合,使得组合里所有元素和为目标值。要求:

1)每个组合里的元素按照升序排列。

2)输出组合里不含有重复的组合。

3)输入序列中的整数可以多次使用。

 

举例:

输入{2347},目标值为7

输出{7}{223}{34}

 

问题分析

为了让输出元素按升序排列,可对输入序列进行排序。同这里我们使用递归的方法来解决这个组合问题,即典型的for语句内调用递归函数。需要注意以下几点:

1)记录剩余目标值和,只有当该值为0时,组合才是有效的。

2)记录当前位置,因为序列中的数可以重复使用,所以下一次递归时,还可以从当前位置开始,这将体现在递归函数的参数里。

具体可参看代码实现中的GetResultSet函数。

 

扩展问题

如果序列中可能有相同的元素,并且每个元素最多只能使用一次,那么又该怎么处理?相对于之前的问题,这里有两个变化:1)每个元素最多只能使用一次,下次递归时是不能从当前位置开始的,而是从下一个开始。2)由于序列中含有相等的元素,哪怕每个元素最多只使用一次,也可能出现重复的组合,所以,为了避免重复,只取第一个相同元素。

具体可参看代码实现中的GetResultSetEx函数。

 

代码实现

#include <iostream>#include <vector>#include <algorithm>using namespace std;typedef vector<int> IntArray; //结果集typedef vector<vector<int>> ResultSet; ResultSet gResultSet;//原始序列中不含相同的值void GetResultSet( const IntArray& mSrcArray, int nTarget,   IntArray& mDstArray, int iStart ){if ( nTarget < 0 ) return;if ( nTarget == 0 ){//找到一个结果gResultSet.push_back( mDstArray );}else{for( int i = iStart; i < mSrcArray.size(); ++i ){//后面更大的数不可能满足条件if ( mSrcArray[i] > nTarget ) break;//加入当前元素mDstArray.push_back( mSrcArray[i] );//递归处理,因为元素可以重复使用,所以从当前位置继续递归GetResultSet( mSrcArray, nTarget-mSrcArray[i], mDstArray, i );//重置mDstArray.pop_back();}}}//序列中可能有相同的元素,并且每个元素最多只能使用一次,不含重复组合void GetResultSetEx( const IntArray& mSrcArray, int nTarget,   IntArray& mDstArray, int iStart ){if ( nTarget < 0 ) return;if ( nTarget == 0 ){//找到一个结果gResultSet.push_back( mDstArray );}else{for( int i = iStart; i < mSrcArray.size(); ++i ){//后面更大的数不可能满足条件if ( mSrcArray[i] > nTarget ) break;//避免结果集重复,只取第一个相同值加入结果中if ( i != iStart && mSrcArray[i] == mSrcArray[i-1] ) continue;//加入当前元素mDstArray.push_back( mSrcArray[i] );////递归处理,因为元素可以重复使用,所以从当前位置继续递归//GetResultSet( mSrcArray, nTarget-mSrcArray[i], mDstArray, i );//递归处理,因为元素不可以重复使用,所以从下一位置继续递归GetResultSetEx( mSrcArray, nTarget-mSrcArray[i], mDstArray, i+1 );//重置mDstArray.pop_back();}}}//输出结果集void OutPutResultSet(){if ( gResultSet.size() <= 20 ){for( ResultSet::iterator it = gResultSet.begin(); it != gResultSet.end(); ++it ){for( IntArray::iterator itTemp = it->begin(); itTemp != it->end(); ++itTemp ){cout << *itTemp << " ";}cout << endl;}}cout << "总共结果数:" << gResultSet.size() << endl;cout << "---------------------------------------" << endl;}int main(){IntArray mSrcArray;IntArray mDstArrayTemp;int nTarget = 0;while( true ){//构造源数据int nTemp = 0;mSrcArray.clear();while( cin >> nTemp ){if ( nTemp == 0 ) break;mSrcArray.push_back( nTemp );}cin >> nTarget;//从小到大排序sort( mSrcArray.begin(), mSrcArray.end() );mDstArrayTemp.clear();gResultSet.clear();//GetResultSet( mSrcArray, nTarget, mDstArrayTemp, 0 );GetResultSetEx( mSrcArray, nTarget, mDstArrayTemp, 0 );//输出结果OutPutResultSet();}return 0;}


 


系列文章说明:
1.本系列文章[算法练习],仅仅是本人学习过程的一个记录以及自我激励,没有什么说教的意思。如果能给读者带来些许知识及感悟,那是我的荣幸。
2.本系列文章是本人学习陈东锋老师《进军硅谷,程序员面试揭秘》一书而写的一些心得体会,文章大多数观点均来自此书,特此说明!
3.文章之中,难免有诸多的错误与不足,欢迎读者批评指正,谢谢.


作者:山丘儿
转载请标明出处,谢谢。原文地址:http://blog.csdn.net/s634772208/article/details/46710405


 

0 0
原创粉丝点击