また rscの日記さんのところにあった問題です。おもしろそうなので Ruby で解いてみました。元の問題はこれです。
問題をコピペしておきます。
円卓の判断推理 問題
A~E の5人が円卓に等間隔で着席している。5人のうち女性は2人で、この2人の席は隣り合っていない。
5人はそれぞれ赤,青,白,黒,緑のシャツを着ており,同じ色のシャツを着ている者はいない。A~D の4人が以下のように述べている。
A「私の左隣には黒いシャツを着た人が座っており,その左隣は男性である」
B「私の右隣には白いシャツを着た人が座っており,その右隣は女性である。」
C「私の左隣には緑のシャツを着た人が座っており,その左隣は男性である」
D「私の隣には青いシャツを着た人が座っている。私ともう1人の両隣に座ってい
る人のシャツは黒ではない。」
この場合で考えられる座席パターンを教えてください。
円順列なので A を固定しています。あとはシンプルなので特に問題はないと思います。変数 $po, sex, col
にはそれぞれ位置、性(:m が男性、:f が女性)、色がハッシュで入っています。
class Symbol def left; $po.key(($po[self] - 1) % 5); end def right; $po.key(($po[self] + 1) % 5); end end def neighbor(sex) ar = [] sex.each_key {|k| ar << $po[k] if sex[k] == :f} ar.sort! (ar[0] + 1 == ar[1]) or (ar[0] == 0 and ar[1] == 4) end ans = [] [1, 2, 3, 4].permutation(4) do |ps| $po = {:A=>0} $po[:B] = ps[0]; $po[:C] = ps[1]; $po[:D] = ps[2]; $po[:E] = ps[3] [:A, :B, :C, :D, :E].combination(2) do |s| sex = {:A=>:m, :B=>:m, :C=>:m, :D=>:m, :E=>:m} sex[s[0]] = :f; sex[s[1]] = :f next if neighbor(sex) [:A, :B, :C, :D, :E].permutation(5) do |c| col = {} col[c[0]] = "赤"; col[c[1]] = "青"; col[c[2]] = "白" col[c[3]] = "黒"; col[c[4]] = "緑" next if col[:D] == "黒" if (col[:A.left] == "黒" and sex[:A.left.left] == :m) and (col[:B.right] == "白" and sex[:B.right.right] == :f) and (col[:C.left] == "緑" and sex[:C.left.left] == :m) and ( (col[:D.left] == "青" and col[:D.right] != "黒") or (col[:D.right] == "青" and col[:D.left] != "黒") ) then ans << [$po, sex, col] end end end end p ans
答えは
[[{:A=>0, :B=>2, :C=>3, :D=>1, :E=>4}, {:A=>:m, :B=>:f, :C=>:m, :D=>:m, :E=>:f}, {:D=>"赤", :A=>"青", :C=>"白", :E=>"黒", :B=>"緑"}], [{:A=>0, :B=>4, :C=>2, :D=>1, :E=>3}, {:A=>:m, :B=>:f, :C=>:m, :D=>:f, :E=>:m}, {:E=>"赤", :C=>"青", :A=>"白", :B=>"黒", :D=>"緑"}]]
と出力されます。左まわりに「(A男青)(D男赤)(B女緑)(C男白)(E女黒)」か「(A男白)(D女緑)(C男青)(E男赤)(B女黒)」と並ぶのが最終的な回答になります。