2013-03-09 7 views
5

可能な限り多くのスーパーセットの要素を含み、相互排他的であるセットのすべてのサブセットを検索したいと思います。少なくともexclusion(a, b) == exclusion(b, a)が成り立つC#ジェネレータを介した最大独立サブセットのセット

bool exclusion<T>(T a, T b) 

:ユーザーが排他のための意味を定義するところ。

そしてexclusion(a, b) == trueが保証されている場合a.Equals(b) == true

私のコードは次のようになります。

public static HashSet<HashSet<T>> MutuallyExclusive<T>(this IEnumerable<T> available, Func<T, T, bool> exclusion) { 
    HashSet<HashSet<T>> finished = new HashSet<HashSet<T>>(new HashSetEquality<T>()); 
    Recursion<T>(available, new HashSet<T>(), finished, exclusion); 
    return finished; 
} 

private static void Recursion<T>(IEnumerable<T> available, HashSet<T> accepted, HashSet<HashSet<T>> finished, Func<T, T, bool> exclusion) { 
    if (!available.Any()) 
     finished.Add(accepted); 
    else 
     foreach (T a in available) 
      Recursion<T>(available.Where(b => !exclusion(a, b)), new HashSet<T>(accepted) { a }, finished, exclusion); 
} 

private class HashSetEquality<T> : IEqualityComparer<HashSet<T>> { 
    public bool Equals(HashSet<T> x, HashSet<T> y) { 
     if (x.Count != y.Count) 
      return false; 
     return x.All(t => y.Contains(t)); 
    } 

    public int GetHashCode(HashSet<T> obj) { 
     return obj.Aggregate(0, (i, t) => i^t.GetHashCode()); 
    } 
} 

は受け入れられる値一つ一つを移動するイテレータにこのコードをオンにする方法はありますか?

編集:

それは私が私の質問では、私は少しunpreciseだったようで、申し訳ありません。私は実際に実行のためにGeneratorを探していました。 、唯一の次受け入れられたセットが

+0

ほかにもxorでハッシュコードを計算すると、すべての値gethashcodeが最良の方法ではありません。 –

+0

@MitchWheatどのように改善するのですか? – Maxwell

+0

だから、あなたはすべての[最大独立セット](http://en.wikipedia.org/wiki/Maximal_independent_set)を探していますか? – svick

答えて

2

、何がやりたいことは、新しいセットにあなたがfinished.Add()を呼び出し、それがtrueを返すたびに得るためです。

しかし、再帰のために、再帰呼び出しから返されるすべての値も返す必要があります。それはおそらく最も効率的な解決策ではないのですが、それは仕事を取得します

public static IEnumerable<HashSet<T>> MutuallyExclusive<T>(
    this IEnumerable<T> available, Func<T, T, bool> exclusion) 
{ 
    var finished = new HashSet<HashSet<T>>(new HashSetEquality<T>()); 
    return Recursion<T>(available, new HashSet<T>(), finished, exclusion); 
} 

private static IEnumerable<HashSet<T>> Recursion<T>(
    IEnumerable<T> available, HashSet<T> accepted, HashSet<HashSet<T>> finished, 
    Func<T, T, bool> exclusion) 
{ 
    if (!available.Any()) 
    { 
     if (finished.Add(accepted)) 
      yield return finished; 
    } 
    else 
     foreach (T a in available) 
     { 
      var results = Recursion<T>(
       available.Where(b => !exclusion(a, b)), 
       new HashSet<T>(accepted) { a }, finished, exclusion); 

      foreach (var set in results) 
       yield return set; 
     } 
} 

:あなたはそのループ内のすべてのそれらの値をもたらすことによって行うことができます。

また、すべてのサブセットを1回だけ実行することもできます。そうすれば、finishedのセットは必要なくなり、見つけたすべての結果を直接得ることができます。

-1

代わりのreturn finished;を計算し、あなたがそれを呼び出すたびに、あなたは

foreach (HashSet<T> set in finished) 
    yield return set; 

を使用することができますそして、あなたは発電機を作っているので、(私はそれが彼らが呼ばているものだと思う?)ように、 MutuallyExclusiveの署名をHashSet<HashSet<T>>からIEnumerable<HashSet<T>>に変更する必要があります。そこで、基本的MutuallyExclusiveは、次のようになります。

基本的に
public static IEnumerable<HashSet<T>> MutuallyExclusive<T>(this IEnumerable<T> available, Func<T, T, bool> exclusion) 
{ 
    HashSet<HashSet<T>> finished = new HashSet<HashSet<T>>(new HashSetEquality<T>()); 
    Recursion<T>(available, new HashSet<T>(), finished, exclusion); 
    foreach (HashSet<T> set in finished) 
     yield return set; 
} 
+0

これは何も役に立ちませんが、最初のアイテムは、セット全体が計算された後にのみ返されます。 – svick

関連する問題