首先,让我们仔细描述您的问题。
关系是一个函数,它接受两个参数并返回一个布尔值,指示关系是否成立。例如,“小于”是一个关系。
等价关系是一种自反关系——每个项目都与自身相关——对称——如果 A 与 B 相关,则 B 与 A 相关——以及传递——如果 A 与 B 相关且 B 相关与 C 相关,则 A 与 C 相关。
等价关系形成一个集合的等价划分;也就是说,许多子集,其中每个子集中的每个元素都相互关联。每个子集称为一个等价类。例如,整数“A和B是相关的,如果它们的差能被3整除”的等价关系形成三个等价类:
{0, 3, -3, 6, -6, ... }
{1, 4, -2, 7, -5, ... }
{2, 5, -1, 8, -4, ... }
您希望形成所有集合的并集:
{1, 2, 3, 4} U {2, 3, 4} U {1, 4} U {1} --> {1, 2, 3, 4}
然后将该集合划分为等价类,其中等价关系是“当且仅当 A 和 B 在每个原始集合中总是一起出现时,A 和 B 是相关的”。
首先形成一个字典,将每个元素映射到其相关的等价类。正如您正确指出的那样,最坏的情况是我们有等价划分,其中每个等价类只包含一个元素,所以让我们从它开始。(顺便说一下,这是“A 等于 B”等价关系的等价划分。)
1 --> { 1 }
2 --> { 2 }
3 --> { 3 }
4 --> { 4 }
现在从联合中生成所有无序对的集合:
{ {1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4} }
现在对于这些无序对中的每一个,问一个问题“这对关系是否成立”?
对于{1, 2}
, {1, 3}
, {1, 4}
, 关系不成立。
因为{2, 3}
关系确实成立,所以将2
和3
桶合并在一起:
1 --> { 1 }
2 --\
--> { 2, 3 }
3 --/
4 --> { 4 }
因为{2, 4}
和{3, 4}
关系不成立。
现在你已经完成了,你有一个从每个元素到其对应的等价类的映射。
说得通?
一旦你把它弄对了,有很多方法可以优化这个算法。先把它弄对。
请注意我在这里所做的:我通过解决等价分区的一般问题解决了您的具体问题。如果您对如何编写此程序很聪明,您将能够重用逻辑来解决任何等价分区问题,而不仅仅是您的特定问题。