查找彩票组合的排名

时间:2014-06-14 12:10:35

标签: combinatorics

我需要找到彩票组合的排名/指数,并能够逆转这个过程(根据排名找到彩票组合)。

考虑一个彩票游戏,其中5个球从1到45,1个强力球从1到20.重复是不允许的,顺序无关紧要。组合数量为:

(45 * 44 * 43 * 42 * 41 / 5!) * 20 = 24,435,180

第一个组合(索引0)是:

1, 2, 3, 4, 5, 1

最后一个组合(索引24,435,179)是:

41, 42, 43, 44, 45, 20

如何在不详尽列举所有组合的情况下将组合转换为索引,反之亦然?

我遇到了this MSDN文章,该文章展示了如何获取给定索引的组合。但是,我不知道如何从组合中获取索引。我试过了:

Choose(c1,k) + Choose(c2,k-1) + Choose(c3,k-2) + Choose(c4,k-3) ...

其中ci是有序组合集中位置i的数字,k是集合的大小。由于组合的索引取决于元素的范围,因此不起作用。另外,我不确定它是否适用于集合中不同大小的元素(例如主池的范围是1-45,强力球的范围是1-20)

1 个答案:

答案 0 :(得分:2)

我能够弄清楚。我创建了一个基于MSDN example的新组合类,它可以将组合转换为索引,反之亦然。为每个数字池检索单独的索引。然后将所有指数组合起来以表示与不同大小的元素的组合。

还创建了一个Pool类来表示池的设置(元素范围,大小等)。 Pool类:

public class Pool {
    public int From { get; set; }
    public int To { get; set; }
    public int Size { get; set; }
    public int Numbers { get { return (To - From + 1); } }
    public Pool(int From, int To, int Size) {
        this.From = From;
        this.To = To;
        this.Size = Size ;
    }
}

组合课程:

class Combination {

    public Pool[] Pools { get; set; }
    public long[][] Data { get; set; } //First index represents pool index, second represents the numbers

    public Combination(Pool[] Pools, long[][] Data) {
        this.Pools = Pools;
        this.Data = Data;
        if (Data.GetLength(0) != Pools.Length) {
            throw (new ArgumentException("Invalid data length"));
        }

        for (int i = 0; i < Data.GetLength(0); i++) {
            if (Data[i].Length != Pools[i].Size) {
                throw (new ArgumentException("Invalid data length"));
            }
        }
    }

    public static Combination FromIndex(long Index, Pool[] Pools) {
        long[][] elements = new long[Pools.Length][];

        long[] c = new long[Pools.Length - 1];
        long cumulative = 1;
        for (int i = 0; i < Pools.Length - 1; i++) {
            c[i] = Combination.Choose(Pools[i].Numbers, Pools[i].Size);
            checked {
                cumulative *= c[i];
            }
        }

        for (int i = Pools.Length - 1; i >= 1; i--) {
            long ind = Index / cumulative;
            Index -= ind * cumulative;

            cumulative /= c[i - 1];
            elements[i] = Combination.FromIndex(ind, Pools[i]);
        }
        elements[0] = Combination.FromIndex(Index, Pools[0]);


        return (new Combination(Pools, elements));
    }

    public static long[] FromIndex(long Index, Pool Pool) {
        long[] ans = new long[Pool.Size];
        long a = (long)Pool.Numbers;
        long b = (long)Pool.Size;
        long x = GetDual((long)Pool.Numbers, (long)Pool.Size, Index);

        for (int k = 0; k < Pool.Size; k++) {
            ans[k] = LargestV(a, b, x);
            x -= Choose(ans[k], b);
            a = ans[k];
            b--;
        }

        for (int k = 0; k < Pool.Size; k++) {
            ans[k] = ((long)Pool.Numbers - 1) - ans[k];
        }


        //Transform to relative
        for (int i = 0; i < ans.Length; i++) {
            ans[i] += Pool.From;
        }

        return (ans);
    }

    private static long GetDual(long To, long Size, long m) {
        return (Choose(To, Size) - 1) - m;
    }

    public static long Choose(long To, long Size) {
        if (To < 0 || Size < 0)
            throw new Exception("Invalid negative parameter in Choose()");
        if (To < Size)
            return 0;  // special case
        if (To == Size)
            return 1;

        long delta, iMax;

        if (Size < To - Size) {
            delta = To - Size;
            iMax = Size;
        } else {
            delta = Size;
            iMax = To - Size;
        }

        long ans = delta + 1;

        for (long i = 2; i <= iMax; ++i) {
            checked {
                ans = (ans * (delta + i)) / i;
            }
        }

        return ans;
    }

    private static long LargestV(long a, long b, long x) {
        long v = a - 1;

        while (Choose(v, b) > x)
            --v;

        return v;
    }

    public long ToIndex() {
        long Index = 0;
        long cumulative = 1;

        for (int i = 0; i < Pools.Length; i++) {
            checked {
                Index += ToIndex(i) * cumulative;
                cumulative *= Combination.Choose(Pools[i].Numbers, Pools[i].Size);
            }
        }

        return (Index);

    }

    public long ToIndex(int PoolIndex) {
        long ind = 0;
        for (int i = 0; i < Pools[PoolIndex].Size; i++) {
            long d = (Pools[PoolIndex].Numbers - 1) - (Data[PoolIndex][i] - Pools[PoolIndex].From);
            ind += Choose(d, Pools[PoolIndex].Size - i);
        }

        ind = GetDual(Pools[PoolIndex].Numbers, Pools[PoolIndex].Size, ind);
        return (ind);
    }

    public override string ToString() {
        string s = "{ ";

        for (int i = 0; i < Data.Length; ++i) {
            for (int k = 0; k < Data[i].Length; k++) {
                s += Data[i][k] + " ";
            }
            if (i != Data.Length - 1) {
                s += "| ";
            }
        }
        s += "}";
        return s;
    }
}

要看到这一点:

        //Create pools
        Pool[] pools = new Pool[2];
        pools[0] = new Pool(1, 45, 5);
        pools[1] = new Pool(1, 20, 1);

        //Create a combination
        long[][] data = new long[][] { new long[] { 41, 42, 43, 44, 45 }, new long[] { 20 } };
        Combination combination = new Combination(pools, data);

        //Get index from combination:
        long index = combination.ToIndex(); 
        Console.WriteLine("Index: " + index);

        //Get combination from index:
        Combination combFromIndex = Combination.FromIndex(index, pools);
        Console.WriteLine("Combination: " + combFromIndex);

输出:

Index: 24435179
Combination: { 41 42 43 44 45 | 20 }