关于从不同数字组中选择2个数字的方法的数量的C#解决方案

时间:2017-03-10 08:27:19

标签: c# algorithm data-structures time-complexity number-theory

我试图解决的问题是这样的。

我已经N,告诉我数字的范围是01...N-2,{{1} }。

我也给了配对,告诉我这些数字对在同一个"组"。

前:

N-1N=60已配对,11已配对,42为配对,我知道其余的数字都在他们自己的组中。

然后我知道分组是3{0, 1, 4}{2, 3}

在这些群组中从不同群组中选择两个号码的方式的数量是{5},这是我尝试解决的数字。这些选择是:

11{0,2}{0,3}{0,5}{1,2}{1,3}{1,5}{4,2}{4,3}{4,5}{2,5}

有人可以帮助弄清楚我的逻辑错在哪里吗?因为我没有通过更大的测试用例并传递较小的测试用例。

我的代码:

{3,5}

例如,我正在传递

    static int Combinations(int N, int K)
    {
        decimal result = 1;
        for (int i = 1; i <= K; i++)
        {
            result *= N - (K - i);
            result /= i;
        }
        return (int)result;
    }

    /// <summary>
    /// Given a set of n numbers 0, 1, ..., n-1 and a list of pairs
    /// of the numbers from the set where each pair (i,j) means that
    /// number i and j are in the same group, find the number of ways
    /// to choose 2 numbers that are not in the same group.
    /// </summary>
    static int PoliticallyCorrectPairs(int n, Tuple<int, int>[] pairs)
    {
        // Create a map that from each number to a number representing
        // the group that it is in. For example, if n = 5 and 
        // pairs = { (0, 1), (2, 3), (0, 4) }, then the map will look 
        // like 
        // 0 -> 1
        // 1 -> 1
        // 2 -> 2
        // 3 -> 2
        // 4 -> 1
        // indicating that 0,1,4 belong to one group and 2,3 to the other.
        int[] gmap = new int[n];
        int k = 1;
        foreach(Tuple<int, int> pair in pairs)
        {
            int i = pair.Item1,
                j = pair.Item2;

            // If both i and j are already in groups, combine those into a
            // single group if it isn't already.
            if (gmap[i] != 0 && gmap[j] != 0)
            {

                if(gmap[i] != gmap[j])
                {
                    for(int m = 0; m < n; ++m)
                        if(gmap[m] == gmap[j])
                            gmap[m] = gmap[i];
                }
            }
            else if(gmap[j] != 0) // j is in a group and i isn't
                gmap[i] = gmap[j]; // add i to j's group
            else if(gmap[i] != 0) // i is in a group and j isn't
                gmap[j] = gmap[i]; // add j to i's group
            else 
                gmap[i] = gmap[j] = k++; // Put both in same new group.
        }
        // Those not assigned to a group each end up in a group alone.
        for(int i = 0; i < gmap.Length; ++i)
            if(gmap[i] == 0)
                gmap[i] = k++;

        // Get the group sizes as an array.
        int[] gcnts = gmap.GroupBy(x => x).Select(g => g.Count()).ToArray();

        // Total number of ways to choose pairs of numbers. 
        int totalCombinations = Combinations(n, 2);

        // Number of pairs from previous count that are in the same group.
        int impossibleCombinations = gmap.GroupBy(x => x)
            .Select(g => g.Count())
            .Where(count => count > 1)
            .Sum(count => Combinations(count, 2));

        return totalCombinations - impossibleCombinations;
    }

但失败

    [TestMethod]
    public void Sample1()
    {
        int N = 5;
        Tuple<int, int>[] pairs = new Tuple<int, int>[]
        {
            Tuple.Create(0, 1),
            Tuple.Create(2, 3),
            Tuple.Create(0, 4)
        };
        Assert.AreEqual(6, PoliticallyCorrectPairs(N, pairs));
    }

知道我哪里出错了吗?

1 个答案:

答案 0 :(得分:2)

问题出在结合部分:

if(gmap[i] != gmap[j])
{
    for(int m = 0; m < n; ++m)
        if(gmap[m] == gmap[j]) // here
            gmap[m] = gmap[i];
}

m点击j时,gmap[j]会被gmap[i]替换,因此会根据gmap[i]检查其余元素。

只需将替换后的值放入局部变量:

if(gmap[i] != gmap[j])
{
    int g = gmap[j];
    for(int m = 0; m < n; ++m)
        if(gmap[m] == g)
            gmap[m] = gmap[i];
}