组合个数
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合的个数。
/// <paramref name="m"/> >= 0; <paramref name="n"/> >= 0
/// </summary>
public static int BinomialCoefficient(int n, int m)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n should be nonegative");
if (m < 0)
throw new ArgumentOutOfRangeException("m should be nonegative");
if (n < m) return 0;
if (n == m) return 1;
if (m == 0) return 1;
return BinomialCoefficient(n - 1, m - 1) + BinomialCoefficient(n - 1, m);
}
Lexicographic(字典顺序)
给定两个整数n, m(1 < m < n),升序返回int[]集合,数组里的数字代表索引。譬如n = 6, m = 3时,返回
210,310,320,321,410,420,421,430,431,432,510,520,521,530,531,532,540,541,542,543
对于任意n个元素的集合,根据索引选取对应元素就可以得到该集合的所有m个元素组合。
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合。
/// </summary>
public static IEnumerable<int[]> Lexicographic(int n, int m)
{
if (n < 2)
throw new ArgumentOutOfRangeException("n shouble be greater than 1");
if (m < 1 || m > n)
throw new ArgumentOutOfRangeException("m shouble be positive and not greater than " + n);
var pos = new int[m + 3];
pos[m + 1] = n;
for (int i = 1; i <= m; ++i)
pos[i] = i - 1;
var result = new List<int[]>();
while (true)
{
var combination = pos.Skip(1).Take(m).Reverse().ToArray();
result.Add(combination);
var index = 1;
while (pos[index] + 1 == pos[index + 1])
{
pos[index] = index - 1;
++index;
}
if (index > m) break;
++pos[index];
}
return result;
}
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合。
/// </summary>
public static IEnumerable<int[]> FastLexicographic(int n, int m)
{
if (n < 2)
throw new ArgumentOutOfRangeException("n shouble be greater than 1");
if (m < 1 || m > n)
throw new ArgumentOutOfRangeException("m shouble be positive and not greater than " + n);
var pos = new int[m + 3];
pos[m + 1] = n;
for (int i = 1; i <= m; ++i)
pos[i] = i - 1;
var result = new List<int[]>();
var index = m;
while (true)
{
var combination = pos.Skip(1).Take(m).Reverse().ToArray();
result.Add(combination);
int tmp;
if (index > 0)
tmp = index;
else
{
if (pos[1] + 1 < pos[2])
{
++pos[1];
continue;
}
else
index = 2;
while (true)
{
pos[index - 1] = index - 2;
tmp = pos[index] + 1;
if (tmp != pos[index + 1]) break;
++index;
}
if (index > m) break;
}
pos[index] = tmp;
--index;
}
return result;
}
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合。
/// </summary>
public static IEnumerable<int[]> DecreasingLexicographic(int n, int m)
{
if (n < 2)
throw new ArgumentOutOfRangeException("n shouble be greater than 1");
if (m < 1 || m > n)
throw new ArgumentOutOfRangeException("m shouble be positive and not greater than " + n);
var pos = new int[m + 1];
for (int i = 1; i < pos.Length; ++i)
pos[i] = i + n - m - 1;
var result = new List<int[]>();
var index = 1;
while (true)
{
var combination = pos.Skip(1).Take(m).Reverse().ToArray();
result.Add(combination);
if (index > m) break;
--pos[index];
if (pos[index] < index)
{
++index;
continue;
}
while (index > 1)
{
pos[index - 1] = pos[index] - 1;
--index;
}
}
return result;
}
Revolving-Door
n = 6, m = 3时返回
210,320,321,310,430,431,432,420,421,410,540,541,542,543,530,531,532,520,521,510
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合。
/// </summary>
public static IEnumerable<int[]> RevolvingDoor(int n, int m)
{
if (n < 2)
throw new ArgumentOutOfRangeException("n shouble be greater than 1");
if (m < 1 || m > n)
throw new ArgumentOutOfRangeException("m shouble be positive and not greater than " + n);
var pos = new int[m + 3];
pos[m + 1] = n;
for (int i = 1; i <= m; ++i)
pos[i] = i - 1;
var result = new List<int[]>();
var flag = true;
while (flag)
{
var combination = pos.Skip(1).Take(m).Reverse().ToArray();
result.Add(combination);
var condition = false;
int index;
if (IsEven(m))
{
if (pos[1] > 0)
{
--pos[1];
continue;
}
else
{
index = 2;
condition = true;
}
}
else
{
if (pos[1] + 1 < pos[2])
{
++pos[1];
continue;
}
else
index = 2;
}
while (true)
{
if (!condition)
{
if (pos[index] >= index)
{
pos[index] = pos[index - 1];
pos[index - 1] = index - 2;
break;
}
else
++index;
}
else
condition = false;
if (pos[index] + 1 < pos[index + 1])
{
pos[index - 1] = pos[index];
++pos[index];
break;
}
else if (++index > m)
{
flag = false;
break;
}
}
}
return result;
}
Chase Sequence(这几个方法中最好的组合方法)
/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合。
/// </summary>
public static IEnumerable<int[]> ChaseSequence(int n, int m)
{
if (n < 2)
throw new ArgumentOutOfRangeException("n shouble be greater than 1");
if (m < 1 || m > n)
throw new ArgumentOutOfRangeException("m shouble be positive and not greater than " + n);
var pos = new int[n];
for (var i = n - m; i < pos.Length; ++i)
pos[i] = 1;
var aux = new int[n + 1];
Array.Fill(aux, 1);
var result = new List<int[]>();
var tmp = n - m;
while (true)
{
var combination = new int[m];
for (int i = 0, j = 0; i < pos.Length; ++i)
if (pos[i] == 1)
combination[j++] = i;
result.Add(combination);
var index = tmp;
if (aux[index] == 0)
while (aux[index] != 1)
aux[index++] = 1;
if (index == n) break;
aux[index] = 0;
if (pos[index] == 0)
{
if (!IsEven(index) && pos[index - 1] == 0)
{
pos[index] = 1;
pos[index - 2] = 0;
if (tmp == index - 2)
tmp = index;
else if (tmp == index - 1)
tmp = index - 2;
}
else
{
pos[index] = 1;
pos[index - 1] = 0;
if (tmp == index && index > 1)
tmp = index - 1;
else if (tmp == index - 1)
tmp = index;
}
}
else
{
if (IsEven(index) && pos[index - 2] == 0)
{
pos[index - 2] = 1;
pos[index] = 0;
if (tmp == index)
tmp = Math.Max(index - 2, 1);
else if (tmp == index - 2)
tmp = index - 1;
}
else
{
pos[index - 1] = 1;
pos[index] = 0;
if (tmp == index && index > 1)
{
tmp = index - 1;
}
else if (tmp == index - 1)
{
tmp = index;
}
}
}
}
return result;
}
public static bool IsEven(int n) => (n & 1) == 0;
Fixed Length Binary Sequence(n个0和m个1的所有组合)
譬如numberOfZero = 2, numberOfOne = 3返回
11100,01110,10110,11010,01101,10101,01011,00111,10011,11001
/// <summary>
/// 返回长度为<paramref name="numberOfZero"/>+<paramref name="numberOfOne"/>的二进制字符串,
/// 其中包含<paramref name="numberOfZero"/>个0和<paramref name="numberOfOne"/>个1
/// </summary>
public static IEnumerable<string> FixedLengthBinarySequence(int numberOfZero, int numberOfOne)
{
if (numberOfZero < 1)
throw new ArgumentOutOfRangeException("numberOfZero shouble be positive");
if (numberOfOne < 1)
throw new ArgumentOutOfRangeException("numberOfOne shouble be positive");
var Length = numberOfZero + numberOfOne;
var aux = new int[Length + 1];
for (var i = 0; i < numberOfOne; ++i)
aux[i] = 1;
var index1 = numberOfOne - 1;
var index2 = numberOfOne - 1;
var result = new List<string>();
while (true)
{
var temp = aux.Take(Length).ToArray();
result.Add(string.Join("", temp));
aux[index1++] = 0;
if (aux[index1] == 1)
{
aux[index2++] = 1;
continue;
}
if (index1 == Length) break;
aux[index1] = 1;
if (index2 > 0)
{
aux[index2] = 1;
aux[0] = 0;
index1 = 1;
index2 = 0;
}
}
return result;
}
Fenichel(指定长度及最大和值的所有组合)
譬如sum = 2, len = 3返回
200,110,020,101,011,002,100,010,001,000
/// <summary>
/// 返回长度为<paramref name="length"/>的数字字符串,其所有数字字符的和不超过<paramref name="sum"/>
/// </summary>
public static IEnumerable<string> Fenichel(int sum, int length)
{
if (sum < 1)
throw new ArgumentOutOfRangeException("sum shouble be positive");
if (length < 1)
throw new ArgumentOutOfRangeException("length shouble be positive");
var pos = new int[length + 1];
pos[0] = sum;
var index = 0;
var result = new List<string>();
while (true)
{
var temp = pos.Take(length).ToArray();
result.Add(string.Join("", temp));
if (pos[0] == 0)
{
if (index == length) break;
pos[0] = pos[index] - 1;
pos[index++] = 0;
}
else
{
--pos[0];
index = 1;
}
++pos[index];
}
return result;
}