次のグラフがあり (矢印は接続の方向を示します)、黒いノードのクラスターのサイズを数えたいとします。
これは、各ノードが隣接ノードのリストを持つように、ノードのリストとしてメモリに編成されます。node[i].State == 1
任意のノードから始めて、指定されたノードも状態 1 である場合、何個のノードが を持っているかを数えたいと考えていますNode.GetClusterSize()
。 ):
public class Node
{
public Int32 State { get; private set; } // 0 = white; 1 = black;
public Boolean Visited { get; private set; }
public List<Node> InputNeigh { get; private set; } // list of references to
// neighbors nodes
public Int32 GetClusterSize()
{
this.Visited = true;
if (this.State == 1)
{
Int32 s = 1, i = 0;
while (i < this.InputNeigh.Count)
{
if (!this.InputNeigh[i].Visited)
{
s += this.InputNeigh[i].GetClusterSize();
}
i++;
}
this.Visited = false; // this is an important step, I'll explain why
return s;
}
else
{
return 0;
}
}
public void Evolve() { /* doesn't matter for this question */ }
}
ここで、メイン シミュレーションのすべてのタイム ステップですべてのノードのクラスター サイズをカウントするため、ノードを未訪問としてマークする必要があります(ノードの状態は時間とともに変化するため、次のタイム ステップでクラスターのサイズが変わる可能性があります)。
この問題は、オブジェクトのフラグの代わりに、特定の要素が node :に対応するNode
ブール値の外部リストがあり、このリストを function への参照として渡すと、簡単に修正できます。しかし、その後、タイムステップごとにこのリストをリセットする必要があり、コードの速度が低下します (パフォーマンスが重要です!)。i
i
List<Boolean> nodeStatus
Node.GetClusterSize()
上記のコードの失敗は、隣接ノードを反復処理した後、ノードを未訪問として正確にマークしていることです。この状況は、次のツリーでよりよく視覚化されます (左から右にアクセスし、最初に を呼び出すと仮定しますnode[0].GetClusterSize()
)。
深さ優先検索は、上記のツリーの青いパスを反復し、ノード に到達すると、3
すべての隣接ノードが既に訪問されていることを認識し、3
未訪問としてマークして を返しますs = 1
。3
の次の隣人2
が訪問され、未訪問として3
マークされているため (既に訪問されていますが)、再度チェックし、アルゴリズムはStackOverflow
例外に入るか、せいぜい間違ったサイズのクラスターを返します。
したがって、私は2つのアイデアを思いつきましたが、それらを実装する方法はまだわかりません:
1) 幅優先検索アルゴリズムを実装します。この概念を提示された状況に適用する方法はわかりませんが。
2) 深さ優先検索を (再帰的ではなく) シーケンシャルに実装します。それにもかかわらず、私はそれがどのように可能か想像できません。
この問題を無効にするアイデアはありますか? なにか提案を?
前もって感謝します!
PS:グラフはこの例よりもはるかに大きくなる可能性があり、ネットワーク内に複数の黒いクラスターが同時に存在し、互いに切断されている可能性があります。したがって、単に黒い要素を数えるという問題ではありません。