这是我的问题:我有一个(非空但可能不是不同的)集合 s_i 的序列 S,并且对于每个 s_i,需要知道 S(i ≠ j)中有多少个集合 s_j 是 s_i 的子集。
我还需要增量性能:一旦我有了所有的计数,我可以用 s_i 的某个子集替换一组 s_i 并逐步更新计数。
使用纯函数式代码执行所有这些将是一个巨大的优势(我在 Scala 中编写代码)。
由于集合包含是部分排序,我认为解决我的问题的最佳方法是构建一个 DAG,它表示集合的 Hasse 图,边表示包含,并将一个整数值连接到每个节点,表示节点下面的子 dag 加 1。但是,我已经被困了好几天,试图开发从偏序构建 Hasse 图的算法(我们不谈论增量!),即使我认为它会是一些标准的本科材料。
这是我的数据结构:
case class HNode[A] (
val v: A,
val child: List[HNode[A]]) {
val rank = 1 + child.map(_.rank).sum
}
我的 DAG 由根列表和一些部分排序定义:
class Hasse[A](val po: PartialOrdering[A], val roots: List[HNode[A]]) {
def +(v: A): Hasse[A] = new Hasse[A](po, add(v, roots))
private def collect(v: A, roots: List[HNode[A]], collected: List[HNode[A]]): List[HNode[A]] =
if (roots == Nil) collected
else {
val (subsets, remaining) = roots.partition(r => po.lteq(r.v, v))
collect(v, remaining.map(_.child).flatten, subsets.filter(r => !collected.exists(c => po.lteq(r.v, c.v))) ::: collected)
}
}
我被困在这里了。最后我想为 DAG 添加一个新值 v 是:
- 在 DAG 中找到 v 的所有“根子集”rs_i,即 v 的子集,使得 rs_i 的任何超集都不是 v 的子集。这可以通过在图上执行搜索(BFS 或 DFS)很容易地完成(
collect
函数,可能不是最佳的甚至是有缺陷的)。 - 构建新节点 n_v,其子节点是先前找到的 rs_i。
- 现在,让我们找出应该附加 n_v 的位置:对于给定的根列表,找出 v 的超集。如果没有找到,将 n_v 添加到根并从根中删除 n_v 的子集。否则,对超集的孩子递归执行第 3 步。
我还没有完全实现这个算法,但对于我看似简单的问题来说,它似乎是不必要的迂回和非最优的。是否有一些更简单的算法可用(谷歌对此一无所知)?