这篇文章老早就写了,还是在生日那天写的(泪流满面啊……),今晚重温,作为纪念~~~
题目:给出任意数组,和r, 生成所有的组合序列。
例如:int array = {1,2,3,4,5,6,7}, r = 5
输出:12345, 12346, 12347, 12356, 12357, 12367, 12456, 12457, 12467, 12567, 13456, 13457, 13467, 13567, 14567, 23456, 23457, 23467, 23567, 24567, 34567
个数为 C(7,5) = C(7, 2) = 7*6/2 = 21个
典型用途:N个组合中,选取其中最好的一组解。
例如:某公司领导很开恩,1个月30天,随意让你选择20天来上班,那你怎么来安排工作日与休假日来达到最优呢?你可以借助计算机,C(30,20)来加权选取其中一个最优解。
{
int [] indexArray = new int [r]; // 产生序号数组
for ( int i = 0 ; i < r; i ++ ) // 初始化序号数组
indexArray[i] = i;
int index = 0 ; // 生成新组合时,index中要变动的下标
int count = 0 ; // 保证每一行输出一个r-组合
while (index >= 0 ) // 终止条件:index == -1
{
foreach ( int e in indexArray) // 输出r-组合
{
Console.Write(source[e]);
if (( ++ count) % r == 0 ) Console.WriteLine();
}
var maxIndex = source.Length - 1 ; // 开始为最大序号,每次循环结束则 - 1
// 每次index从序号数组最后开始。
for (index = r - 1 ; index >= 0 ; index -- , maxIndex -- ) // 以字典序找新的r-组合
{
if (indexArray[index] < maxIndex)
{
indexArray[index] ++ ; // 增加序号
for ( int j = index + 1 ; j < r; j ++ )
indexArray[j] = indexArray[j - 1 ] + 1 ; // 后面的元素统统按字典序排列
break ;
}
}
}
Console.WriteLine( " 总共有{0}组解 " , count / r);
}
算法参考:http://hi.baidu.com/woiwojia/blog/item/93ec1ade5e5fd55dcdbf1aac.html
同时我还找到一个老外的:http://www.codeproject.com/KB/recipes/Combinatorics.aspx
{
private List < IList < T >> _combinations;
private IList < T > _items;
private int _length;
private int [] _endIndices;
public Combinations(IList < T > itemList)
: this (itemList, itemList.Count)
{
}
public Combinations(IList < T > itemList, int length)
{
_items = itemList;
_length = length;
_combinations = new List < IList < T >> ();
_endIndices = new int [length];
int j = length - 1 ;
for ( int i = _items.Count - 1 ; i > _items.Count - 1 - length; i -- )
{
_endIndices[j] = i;
j -- ;
}
ComputeCombination();
}
private void ComputeCombination()
{
int [] indices = new int [_length];
for ( int i = 0 ; i < _length; i ++ )
{
indices[i] = i;
}
do
{
T[] oneCom = new T[_length];
for ( int k = 0 ; k < _length; k ++ )
{
oneCom[k] = _items[indices[k]];
}
_combinations.Add(oneCom);
}
while (GetNext(indices));
}
private bool GetNext( int [] indices)
{
bool hasMore = true ;
for ( int j = _endIndices.Length - 1 ; j > - 1 ; j -- )
{
if (indices[j] < _endIndices[j])
{
indices[j] ++ ;
for ( int k = 1 ; j + k < _endIndices.Length; k ++ )
{
indices[j + k] = indices[j] + k;
}
break ;
}
else if (j == 0 )
{
hasMore = false ;
}
}
return hasMore;
}
public int Count
{
get { return _combinations.Count; }
}
public IEnumerator < IList < T >> GetEnumerator()
{
return _combinations.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
上面这个可以直接在项目里面用,算法一样,也是字典序法,只是它自己保存了一个_endIndices来做保存结束序号,而我的算法是不需要的,因为我会计算结束序号。;)
算法复杂度,O(N^3),里面有3个内嵌的for循环。
有没有更有的算法呢?同时如何计算C(7,5)的值呢?给你们留个作业吧。