LoginSignup
2
2

More than 5 years have passed since last update.

Groovyでやってみる「全ての部分集合を少ないコストで得る」

Posted at

つまり、

A =\{a_0,..,a_n\}\\
B \subseteq A\\
\forall B(B \in f(A))

となる関数$f(A)$を作ります。
但し、$A=\phi$ のとき $f(A)=\{\phi\}$ としています。

def getSubsets = {l->
  if(!l) return [[]]
  def ss = []
  def x = Integer.parseInt(('1' * l.size()),2)
  for(int y=x;y>0;y=--y&x){
    def s = []
    Integer.toBinaryString(y).padLeft(8, '0').reverse().eachWithIndex{flg,idx->
      if(flg=='1') s << l[idx]
    }
    ss << s
  }
  ss
}

ビット演算y=--y&xがこの計算の要旨で、これはビットの部分集合を得ます。
よくわからない場合は真偽表でも書いて確かめてみてください。

リストのサイズのBit表現の部分集合の逆順リストのフラグ位置を求めることで、任意のリストの部分集合を得られます。

groovy> def list = [1,2,3] 
groovy> getSubset(list) 

Result: [[1, 2, 3], [2, 3], [1, 3], [3], [1, 2], [2], [1]]

なお、わかると思いますが、この関数に長いリストを叩き込むと出力がどエライことになります。

部分集合を引数としてとるクロージャを引数として取る関数にして、それぞれの部分集合に対する(返却すべき)演算結果のリストを返すくらいにしておいたほうが無難だと思います。

参考:http://d.hatena.ne.jp/deve68/?of=40

2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2