C#解决从不同数字组中选择2个数字的多种方法

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

我要解决的问题是这样的。

我得到了 N,告诉我数字的范围是 0, 1, ...N-2N-1

我也得到了配对,告诉我这些数字对在同一个“组”中。

例如:

N=601配对,14 是成对的,23 是成对的,我知道剩下的数字是自己的组。

然后我知道分组是 {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));
    }

但是失败了

    [TestMethod]
    public void TestCase2()
    {
        int N = 100;
        Tuple<int, int>[] pairs =
@"0 11
2 4
2 95
3 48
4 85
4 95
5 67
5 83
5 42
6 76
9 31
9 22
9 55
10 61
10 38
11 96
11 41
12 60
12 69
14 80
14 99
14 46
15 42
15 75
16 87
16 71
18 99
18 44
19 26
19 59
19 60
20 89
21 69
22 96
22 60
23 88
24 73
27 29
30 32
31 62
32 71
33 43
33 47
35 51
35 75
37 89
37 95
38 83
39 53
41 84
42 76
44 85
45 47
46 65
47 49
47 94
50 55
51 99
53 99
56 78
66 99
71 78
73 98
76 88
78 97
80 90
83 95
85 92
88 99
88 94"
        .Split('\n')
        .Select(line =>
        {
            int[] twofer = line.Split(' ').Select(s => int.Parse(s)).ToArray();
            return Tuple.Create(twofer[0], twofer[1]);
        })
        .ToArray();
        Assert.AreEqual(3984, PoliticallyCorrectPairs(N, pairs));
    }

知道我哪里出错了吗?

最佳答案

问题出在组合部分:

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];
}

关于C#解决从不同数字组中选择2个数字的多种方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42713622/

相关文章:

algorithm - 如何从堆栈中搜索项目?

c# - ContainsKey VS Try Catch

algorithm - 关于优化和决策版本的装箱

c# - 如何使用 nodatime 验证 IANA 字符串?

algorithm - 如何用一条线分割一个多边形?

c# - 如何从给定的父节点获取所有子节点?

c - 我在 queue.h 中的修改是否由 Berkeley 实现?

c++ - 有没有办法从下面的数据中唯一地构建一个整数?

c# - 尝试激活 Controller 时无法解析类型 'Microsoft.Graph.GraphServiceClient' 的服务

c# - 针对指定 *LIBL 而不是特定库的 AS400 执行 SQL