【问题标题】:Algorithm for calculating all intersects and disjoints for an indefinite number of sets用于计算无限数量集合的所有相交和不相交的算法
【发布时间】:2013-09-02 08:24:53
【问题描述】:

最近我不得不为下面概述的集合问题开发一个朴素的递归算法,但现在想知道问题的正式描述/名称是什么,以及是否有一种算法可以更有效地解决问题(我怀疑有)。

我知道有单独的算法可以找到相交和不相交,但我还没有认识到任何可以涵盖整个问题的算法。

问题:

获取无限数量的集合,并为所有集合的每个相交和不相交返回一个集合。

例如,给定 4 个集合作为输入 A、B、C、D:

一个{1,14,2,10,13,12,8,9}

B {2,3,4,15,11,13,9}

C {13,10,4,15,5,6,12,11}

D {7,8,9,13,11,6,12}

结果应该是以下13套:

{1,14},{2},{3},{4,15},{5},{6},{7},{8},{9},{10},{11} ,{12},{13}

我开发的算法很幼稚,因为它递归地比较所有集合排列(我希望能够在 XSLT 2.0 中相对容易地实现这一点),直到找不到进一步的相交。

在某些情况下,我需要执行此操作来描述树的多个版本如何在树上的每个点修改原始树。 “树”实际上是一个 XML 文档。

[更新] 在接受的答案中显示第一个算法针对 3 个集合运行: {1,2,3},{2,3,4},{2,3,5}

与我原来的 nieve 算法运行 3 组相比:

【问题讨论】:

    标签: algorithm set


    【解决方案1】:

    一旦明确了一些设置的属性,问题就变得很容易了。

    A int B int C = ( A int B ) int C
    

    这告诉我们,我们可以解决 2 个集合的问题,然后将每个结果与第三个集合相交,以此类推。

    通过解决 hte 问题,我的意思很简单,A int B 生成 3 个集合:

    A op B => A int B , A - (A int B) , B - (A int B)
    

    一旦清楚了,实现就很简单了,应该如下所示:

    resultset = emptyset
    while ( queue not empty )
       tmpset = emptyset
       A = queue.pop()
       residual = A
       for B in resultset
         tmpset = tmpset + {A int B , B - (A int B)}
         residual = residual - B
       tmpset = tempset + residual
       resultset = tmpset
    

    显然,如果任何集合为空,则不需要将其添加到解决方案中。 这是一些使用字典思想解决问题的 C# 代码:

            var query = arr.Select((x, i) => x.Select(y => new { Elem = y, Index = i }))
                .SelectMany(x => x)
                .GroupBy(x => x.Elem)
                .ToDictionary(x => x.Key, y => new HashSet<int>(y.Select(z => z.Index).ToList()))
                .GroupBy(x => x.Value, HashSet<int>.CreateSetComparer())
                .Select(x=>x.Select(y=>y.Key).ToList())
                .ToList();
    

    【讨论】:

    • +1,因为您已经描述了我使用的“nieve”解决方案比我可以使用的更好(尽管我不熟悉您使用的实现语言),但是有一个名称这个问题,是否有更有效的算法可以避免测试所有排列?
    • 只是补充一点,虽然 A int B 确实如您所述生成 3 个集合,但如果 A 是 B 的子集,则第 3 个集合可能是空集合,反之亦然
    • 这是伪代码,只是真实代码和英语的某种混合。我不认为这个问题有一个特定的名称,我很确定你不能做得比这更好。只是为了清楚起见,您并没有测试所有排列。另一种方法可能是,创建一个类似字典的结构并同时添加一个元素,以及他所属的集合列表。一旦你有了它,创建分区就很容易了。
    • 是的,没有注意到它没有测试所有排列 - 我将通过一些示例进一步测试。
    • 我添加了一些实际的 c# 代码,以“智能”方式解决您的问题。希望对你有帮助
    猜你喜欢
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    相关资源
    最近更新 更多