ここに私の問題があります:私は(空ではないがおそらく明確ではない)セットs_iのシーケンスSを持っており、各s_iについて、S内のセットs_j(i≠j)がs_iのサブセットである数を知る必要があります。
また、インクリメンタル パフォーマンスも必要です。すべてのカウントを取得したら、1 つのセット s_i を s_i のサブセットに置き換えて、カウントをインクリメンタルに更新します。
純粋に機能的なコードを使用してこれらすべてを実行すると、大きなプラスになります (私は Scala でコーディングしています)。
セットの包含は半順序付けであるため、私の問題を解決する最善の方法は、セットのハッセ図を表す DAG を作成し、エッジが包含を表し、整数値を各ノードのサイズを表す結合することであると考えました。ノードの下のサブダグに 1 を加えたものです。ただし、半順序付けからハッセ図を作成するアルゴリズムを開発しようとして数日間行き詰まりました (インクリメンタリティについては話さないでください!)。標準的な学部の資料。
ここに私のデータ構造があります:
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、つまり、rs_i のスーパーセットが v のサブセットではないような v のサブセットを見つけます。これは、グラフで検索 (BFS または DFS) を実行することによって非常に簡単に行うことができます (
collect
関数、おそらく最適ではないか、欠陥がある可能性さえあります)。 - 新しいノード n_v を構築します。その子ノードは以前に見つかった rs_i です。
- 次に、n_v をどこに付けるかを調べましょう: 与えられたルートのリストについて、v のスーパーセットを見つけます。何も見つからない場合は、ルートに n_v を追加し、ルートから n_v のサブセットを削除します。それ以外の場合は、スーパーセットの子に対してステップ 3 を再帰的に実行します。
私はまだこのアルゴリズムを完全に実装していませんが、明らかに単純な問題に対して不必要に回旋しており、最適ではないようです。利用可能な単純なアルゴリズムはありますか (Google はこれについて無知でした)。