過去ログ

まるケン
「すでに座っている人の隣にならない座席が空いている場合には、そちらを選ぶ」
これを ルール1と呼ぶことにします。

ルール1を守れなくなるまでに座れる人数は、座り方によって変わります。
例えば、6席の場合、上手に座れば3人まで座れますが、イとオに座るともう一杯。
N席に座れる最大数は、(N+1)÷2。6席なら3だし、7席、8席なら4人まで座れます。
逆に、9席の場合は、うまく座れば5人座れますが、
イ、オ、ク と座ってしまうと、3人しか座れないこともあります。
これは、N席なら(N+2)/3人と表すことができます。
つまり、9席の場合、最小3人から最大5人の3通りのパターンがあることになります。
今回のアプローチは、N席の場合に、N/3から(N+1)/2 人座れるパターンが、
それぞれの人数に対して何パターンあるかを求めようという作戦です。

さてさて、ここからが Ruby のスクリプト。
掲示板向けに、スペース2つを全角スペースに置き換えています。

# 階乗を求めるのに、Hashを使ってみました。
# 関数にしちゃうと、同じ値でも毎回同じ処理を実行するのに比べ、
# Hashだと、過去に計算したことのある数値なら、
# ほぼ即座に答えが返るんじゃないか?という期待を込めてです。
$f = Hash.new{|h,k|h[k]=k<2?1:h[k-1]*k}

# nCm n個の中からm個を選ぶときの選び方の数
def ncomb(n, m)
 return $f[n] / $f[n-m] / $f[m]
end

# n個の席にm人が、隣に空席をあける条件で座るとき、座り方は何パターンあるか?
def npat(n, m)
 e = n - m    # 空席の総数
 z = m - 1    # 隣に空席をあけなければならない、必須の空席数(3人座るならその間の2か所)
 j = e - z    # あけ足りない空席の数
 k = m + 1    # あけ足りない空席を配置させられる箇所の数(両端と座っている席と席の間)
 s = ncomb(k, j) # k箇所から空席を配置するj個を選ぶ選び方
 return s
end

def sol_1277(n)
 min = (n+2) / 3
 max = (n+1) / 2

 (min..max).each do |m|
  r = npat(n, m)
  # ルール1に従って座る座り方の総数:m人座るなら m!通り
  # ルール1後のに座る座り方の総数:残りn-m人なので(n-m)!通り
  # このパターンがr通りあるので、、、
  $n += $f[m] * $f[n-m] * r
 end
end

(1..100).each do |n|
 $n = 0
 sol_1277(n)
 p [n, $n]
end
おうち   12月17日(日) 16:44:35     52991

過去問題一覧へ戻る