从N个元素中取k个元素子集的减治法实现
2008-04-26 20:03
148 查看
对于n个元素的k个分量的所有组合的减治算法如下:
设有6个元素的集合{ 1,2,3,4,5,6 },现在取其4个分量的所有组合的步骤为:
1. 根据n-k得出从集合中第(k-1)个元素开始取值,即{3},{4},{5},{6},组成2个分量的所有子集。此时对于元素{3},其子集个数应为3个,即{3,4}{3,5}{3,6}:
对于元素{4},其子集个数应为2个,即{4,5}{4,6}:
对于元素{5},其子集个数应为1个,即{5,6}
2. 根据第一步得到的2个分量的子集,添加新的元素{2},组成3个分量的所有子集。此时对于元素{2},其子集个数应为第一步中所有子集的个数,即6个,而对于元素{3},{4},{5},其3个分量的子集个数分别为不以其本身开头的子集个数,分别为:3,1,0。
所以得出的3个分量的所有子集为:
{2,3,4}{2,3,5}{2,3,6}{2,4,5}{2,4,6}{2,5,6}
{3,4,5}{3,4,6}{3,5,6}
{4,5,6}
3. 根据第二步,可知在增加元素{1}之后,元素{1}{2}{3}{4}{5}所对应的4个分量的子集的个数分别为:6+3+1,3+1,1,0,0
所以得到的4个分量的所有子集为:
{1,2,3,4}{1,2,3,5}{1,2,3,6}{1,2,4,5}{1,2,4,6}{1,2,5,6}{1,3,4,5}{1,3,4,6}{1,3,5,6}{1,4,5,6}
{2,3,4,5}{2,3,4,6}{2,3,5,6}{2,4,5,6}
{3,4,5,6}
由上述例子可以推出n个元素k个分量的所有组合的减治算法,开始对k个分量进行i=2个元素的组合,然后每一步增加一个分量,做i+1个分量的组合,直到元素个数为n,此时得出k个元素的所有组合了。
C++代码:
#include <iostream>
#include <vector>
using namespace std;
int C( int n, int m)
{
if ( n == 0 )
return 1;
int res = 1;
int temp = m - n;
for( int i = m; i != temp; --i )
res *= i;
for( int j = n; j > 1; --j )
res /= j;
return res;
}
int main()
{
const int N = 6;
int Array[] = { 1, 2, 3, 4, 5, 6 };
//cout << "Please enter the array" << endl;
//for (int i1 = 0; i1 < N; cin >> Array[i1++]);
//for( int a = 0; a < N; ++a )
//cout << Array[a] << endl;
cout << "Please input K" << endl;
int K;
cin >> K;
int num = N - K + 1;
vector< vector< int > > vec( num ), ivec; //K个元素子集的个数
vector< vector< int > >::iterator it = vec.begin();
for( int i = K - 1; i < N; ++i, ++it ) //先存储第一列数
{
( *it ).push_back( Array[i] );
}
cout << vec.size() << endl;
for( int i1 = 1; i1 < K; ++i1 ) //i1为子集里元素的个数
{
int keyNum = K - i1 - 1;
vector< vector<int> >::iterator old_begin = vec.begin(),
old_end = vec.end();
int index = 0;//辅助控制需要添加新元素的位置
for( int i2 = 0; keyNum < N - i1; ++keyNum, i2 += C( i1 - 1, N - keyNum - 1 ))
{
old_begin = vec.begin() + i2;
copy( old_begin, old_end, back_inserter( ivec ) );
for( vector< vector< int > >::iterator beg = ivec.begin() + index; beg != ivec.end(); ++beg )
{
beg->push_back( Array[keyNum] );
}
index += old_end - old_begin;
}
vec.clear();
copy( ivec.begin(), ivec.end(), back_inserter( vec ) );
ivec.clear();
}
cout << "Here is the result !" << endl;
cout << "There are "
<< vec.size()
<< " subarray"
<< endl;
for( vector< vector<int> >::iterator it = vec.begin(); it != vec.end(); ++it )
{
for( vector<int>::reverse_iterator it1 = (*it).rbegin(); it1 != (*it).rend(); ++it1 )
cout << *it1;
( it + 1 - vec.begin()) % 10 ? cout << " " : cout << endl;
}
return 0;
}
设有6个元素的集合{ 1,2,3,4,5,6 },现在取其4个分量的所有组合的步骤为:
1. 根据n-k得出从集合中第(k-1)个元素开始取值,即{3},{4},{5},{6},组成2个分量的所有子集。此时对于元素{3},其子集个数应为3个,即{3,4}{3,5}{3,6}:
对于元素{4},其子集个数应为2个,即{4,5}{4,6}:
对于元素{5},其子集个数应为1个,即{5,6}
2. 根据第一步得到的2个分量的子集,添加新的元素{2},组成3个分量的所有子集。此时对于元素{2},其子集个数应为第一步中所有子集的个数,即6个,而对于元素{3},{4},{5},其3个分量的子集个数分别为不以其本身开头的子集个数,分别为:3,1,0。
所以得出的3个分量的所有子集为:
{2,3,4}{2,3,5}{2,3,6}{2,4,5}{2,4,6}{2,5,6}
{3,4,5}{3,4,6}{3,5,6}
{4,5,6}
3. 根据第二步,可知在增加元素{1}之后,元素{1}{2}{3}{4}{5}所对应的4个分量的子集的个数分别为:6+3+1,3+1,1,0,0
所以得到的4个分量的所有子集为:
{1,2,3,4}{1,2,3,5}{1,2,3,6}{1,2,4,5}{1,2,4,6}{1,2,5,6}{1,3,4,5}{1,3,4,6}{1,3,5,6}{1,4,5,6}
{2,3,4,5}{2,3,4,6}{2,3,5,6}{2,4,5,6}
{3,4,5,6}
由上述例子可以推出n个元素k个分量的所有组合的减治算法,开始对k个分量进行i=2个元素的组合,然后每一步增加一个分量,做i+1个分量的组合,直到元素个数为n,此时得出k个元素的所有组合了。
C++代码:
#include <iostream>
#include <vector>
using namespace std;
int C( int n, int m)
{
if ( n == 0 )
return 1;
int res = 1;
int temp = m - n;
for( int i = m; i != temp; --i )
res *= i;
for( int j = n; j > 1; --j )
res /= j;
return res;
}
int main()
{
const int N = 6;
int Array[] = { 1, 2, 3, 4, 5, 6 };
//cout << "Please enter the array" << endl;
//for (int i1 = 0; i1 < N; cin >> Array[i1++]);
//for( int a = 0; a < N; ++a )
//cout << Array[a] << endl;
cout << "Please input K" << endl;
int K;
cin >> K;
int num = N - K + 1;
vector< vector< int > > vec( num ), ivec; //K个元素子集的个数
vector< vector< int > >::iterator it = vec.begin();
for( int i = K - 1; i < N; ++i, ++it ) //先存储第一列数
{
( *it ).push_back( Array[i] );
}
cout << vec.size() << endl;
for( int i1 = 1; i1 < K; ++i1 ) //i1为子集里元素的个数
{
int keyNum = K - i1 - 1;
vector< vector<int> >::iterator old_begin = vec.begin(),
old_end = vec.end();
int index = 0;//辅助控制需要添加新元素的位置
for( int i2 = 0; keyNum < N - i1; ++keyNum, i2 += C( i1 - 1, N - keyNum - 1 ))
{
old_begin = vec.begin() + i2;
copy( old_begin, old_end, back_inserter( ivec ) );
for( vector< vector< int > >::iterator beg = ivec.begin() + index; beg != ivec.end(); ++beg )
{
beg->push_back( Array[keyNum] );
}
index += old_end - old_begin;
}
vec.clear();
copy( ivec.begin(), ivec.end(), back_inserter( vec ) );
ivec.clear();
}
cout << "Here is the result !" << endl;
cout << "There are "
<< vec.size()
<< " subarray"
<< endl;
for( vector< vector<int> >::iterator it = vec.begin(); it != vec.end(); ++it )
{
for( vector<int>::reverse_iterator it1 = (*it).rbegin(); it1 != (*it).rend(); ++it1 )
cout << *it1;
( it + 1 - vec.begin()) % 10 ? cout << " " : cout << endl;
}
return 0;
}
相关文章推荐
- 从N个元素中取k个元素子集的c++实现
- 搜狐在线笔试 时间复杂度O(n)实现数组A[n]中所有元素循环左移k个位置
- 集合论32元素以内划分为三个以下的子集(c实现版),没有重复了
- k个元素的子集 C(n,k)
- 列出所有K个元素的子集-----2013年1月26日
- 用priority_queue实现找出数组中前K个大的元素
- Java实现-带重复元素的子集
- 【C语言】递归实现元素的全排列和子集
- 列出所有K个元素的子集-----2013年1月26日
- 列出所有K个元素的子集
- 面试题: 已知一个含有n个不同元素的集合,要求打印其所有具有k个元素的子集(不允许有重复的)
- Java实现集合的组合(从组合中取出K个元素进行组合的所有情况)
- 转:时间复杂度O(n)实现数组A[n]中所有元素循环左移k个位置
- 列出所有K个元素的子集-----2013年1月26日
- 寻找最小的k个数(采用维护k个元素的最大堆的方法来实现)
- 集合的子集生成(无重复元素)
- jquery实现tr元素的上下移动示例代码
- OPhone平台2D游戏引擎实现——场景、图层、元素(一)
- 将数组中指定数量的元素移动数组后面的实现代码
- jq实现点击某元素之外触发事件