【笔记】TAOCP Vol4 - Combination

组合个数

/// <summary>
/// <paramref name="n"/>个元素集合中所有<paramref name="m"/>个元素组合的个数。
/// <paramref name="m"/> &gt;= 0; <paramref name="n"/> &gt;= 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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值