这是我的问题:我有一个由非空但可能不相同的集合$s_i$组成的序列$S$,对于每个$s_i$,需要知道在$S$中有多少个集合$s_j$($i≠j$)是$s_i$的子集。
我还需要实现增量性能:一旦我得到所有计数,我可以通过某些$s_i$的子集替换它,并递增更新计数。
使用纯函数式代码执行所有这些操作将是巨大的加分项(我用Scala编写代码)。
由于集合包含是偏序关系,我认为解决我的问题的最佳方法是构建一个DAG,该DAG表示集合的Hasse图,具有表示包含的边,并在每个节点上连接一个整数值,该值表示下面子DAG的大小加1。然而,尝试从偏序关系构建Hasse图的算法已经困扰了我数天,即使我认为这是一些标准的本科材料。
以下是我的数据结构:
我还需要实现增量性能:一旦我得到所有计数,我可以通过某些$s_i$的子集替换它,并递增更新计数。
使用纯函数式代码执行所有这些操作将是巨大的加分项(我用Scala编写代码)。
由于集合包含是偏序关系,我认为解决我的问题的最佳方法是构建一个DAG,该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)
}
}
我卡在这里了。我目前为止最后想到的是要将新值v添加到DAG中:
- 找到DAG中所有v的"根子集" rs_i,即v的子集,使得rs_i的超集不是v的子集。这可以通过对图执行搜索(BFS或DFS)来实现(
collect
函数,可能是非最优甚至有缺陷的)。 - 构建新节点n_v,其子节点是先前找到的rs_i。
- 现在,让我们找出n_v应该被附加到哪里:对于给定的根列表,找出v的超集。如果没有找到超集,则将n_v添加到根并从根中删除n_v的子集。否则,在超集的子节点上递归执行步骤3。
我还没有完全实现这个算法,但它似乎对我的明显简单问题来说过于复杂和非最优了。是否有某种更简单的可用算法(Google对此毫无头绪)?