Click here to load reader
Upload
shigeichiro-yamasaki
View
464
Download
0
Embed Size (px)
Citation preview
Ruby2.0 で
lazy な N-Queen
e-Zuka Tech Night山崎重一郎
N-Queen
解 [2,4,1,3]
1 2 3 4
[1~N] の順列の生成、テスト
Ruby で順列の生成
> [1,2,3,4].permutation=> #<Enumerator: [1, 2, 3, 4]:permutation>
> [1,2,3,4].permutation.to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]
順列の生成方法
> [1,2,3,4].permutation=> #<Enumerator: [1, 2, 3, 4]:permutation>
> [*1..10].permutation.to_aなかなか返ってこない〜
順列生成を Fiber にするf=->n{Fiber.new{[*1..n].permutation.each{|x|Fiber.yield x}}}
g=f[10]=> #<Fiber:0x00000126282090>
g.resume=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]g.resume=> [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]
g=f[100]g.resume
Ruby 2.0 の lazy順列を lazy に生成
Ruby 1.9の場合は gemで enumerable-lazyを入れてrequire 'enumerable/lazy'
[*1..4].permutation.lazy[*1..4].permutation.lazy.to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4,
1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4,
2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]
[*1..4].permutation.lazy.take(3).to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4]]
Ruby 2.0順列生成を lazy にやる
f=->n{[*1..n].permutation.lazy}g=f[20]g.take(3).to_a=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 19], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 18, 20]]
g.take(4).to_a=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 19], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 18, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 18]]
Fiber 版 N-Queen#斜めチェックd=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}#ファイバー生成関数f=->n{Fiber.new{[*1..n].permutation.each{|x|Fiber.yield x}}}g=f[10]queen=->{p;begin p=g.resume end until diag[p];p}
queen[]=> [1, 3, 6, 8, 10, 5, 9, 2, 4, 7] queen[]=> [1, 3, 6, 9, 7, 10, 4, 2, 5, 8]> queen[]=> [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]
lazy 版 N-Queend=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}f=->n{[*1..n].permutation.lazy}queen=->n{->m{f[n].select{|p|diag[p]}.take(m).to_a}}# takeは、取り出す解の個数
queen[10][1]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7]]queen[10][2]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8]]queen[10][3]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8], [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]]
lazy 版 N-Queend=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}f=->n{[*1..n].permutation.lazy}queen=->n{->m{f[n].take(m).select{|p|diag[p]}.to_a}}#takeの位置を変更して、候補の順列の生成回数にしてみる
queen[10][50000]=> []queen[10][60000]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8], [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]]