设置/映射的集合表示为一个范围数组到一个数组 - 最小化大小?

时间:2018-01-23 15:33:11

标签: algorithm

我有一套地图,比如说

a => {cow, dog}, b => {dog}

并希望将其作为范围地图存储到数组中,例如

a => (start: 0, end: 1), b => (start: 2, end: 2) 
[cow, dog, dog]

当然除外

a => (start: 0, end: 1), b => (start: 1, end: 1)
[cow, dog]

将是一种更有效的表现形式。如何找到最小的解决方案?这让我觉得有些东西会被更多的人研究,但搜索会产生无穷无尽的相关内容。

1 个答案:

答案 0 :(得分:0)

我对你的问题有一些非常不完整的想法,这些想法太长而无法形成评论。

在您的示例中,您的解决方案依赖于

这一事实
P1 = {cow}
P2 = {dog}

是最小的不相交集,并且每个集都是这些集合的(不相交):

S1 = union(P1,P2)
S2 = P2

一个更复杂的例子可能会添加一只猪和一只鸭子,有三组

S1 = {cow,dog,pig}
S2 = {dog,pig}
S3 = {cow,duck}

相应的最小不相交集是

P1 = {cow}
P2 = {dog,pig}
P3 = {duck}

就哪个

而言
S1 = union(P1,P2)
S2 = P2
S3 = union(P1,P3)

道具一般来说,任何有限集合C = {S1,S2,...}的元素都可以细分为最小的不相交分区,这样集合中的每个集合都是一个不相交的集合。一些收集的元素。

证明所有元素的范围都是U = union(S : S in C)。然后,对所有元素P_trivial = {{e} : e in U}的完整分区就是这样一个(非最小的)不相交的分区。由于所有这些不相交分区的集合都是非空的,并且由于它们的大小是有限的,因此通过良好的排序原则存在一个(不一定是唯一的)具有最小尺寸的分区。

任务#1 计算这个最有效的不相交分区。建议的起点是找到每对集合的交集和补充,并从中构建。

现在有了一个有效的不相交的元素分区,每个集合的格式为

S_i = union(P_j : P_j in partition such that contains(i,j)

其中contains(i,j)是二进制谓词,表明集合S_i保留了分区集P_j。您可以将contains(i,j)视为形成一个矩阵,其行数等于集合数,列数等于分区数。在牛/狗的例子中,

contains = 1 1 0
           0 1 0
           1 0 1

请注意,此矩阵的两列不相等。如果列j1等于列j2,则集合将包括分区元素P_j1< =>如果包含P_j2,那么加入P_j1P_j2将是一个更有效的分区。 (也许这是从平凡分区开始寻找最小分区的更好方法。)

两列内容越近,将相应的分区元素放在数组中就越有意义。 “close”的定义可以只是两列相等的行数(即包含或不包含这些分区元素的集合的数量)。这将导致很多关系,并且通过分区元素中的元素数量对此进行加权可能是有意义的。

将这个简单的距离度量(忽略权重)应用于列对会导致“接近”矩阵。对于牛/狗的例子,这将是

3 1 2
1 3 0
2 0 3

这个“接近度”矩阵的伪方程可能是

Closeness = Contains^T (&) Contains

即。矩阵乘法的一个版本。

如果分区元素“紧密”在一起,它们应该连续出现在数组中。对于这个给定的矩阵,这表示顺序

[P2 P1 P3] = [dog, pig, cow, duck]

就这个数组而言,

S1 = range 0 to 2
S2 = range 0 to 1
S3 = range 2 to 3

我通过选择矩阵中最大的非对角线条目来得到这个 - 2,对应于P1和P3,将它们粘在一起。然后,我看着P2是否更靠近P1或P3,并将它粘在它靠近的一侧。当然,我没有把它写成一个完整的算法或证明任何类型的最小化,但我相信它可能会概括:选择最大的非对角线元素,将两个相应的分区元素放在一起,然后链接剩余的分区任何一方的元素。