こちらの問題はpaizaさんにて公開されているBランクの練習問題の自分なりのまとめ、備忘録です。
スキルチェックの公式問題の流出を目的、意図したものではありません。
#問題
うなぎ屋にはとても大きい長テーブルがあり、テーブルの周りにn個の座席が配置されています。
座席には、時計回りに1, 2, …, nと番号が振られています。
座席はテーブルの周りに配置されているので、座席番号nの座席と1の座席は隣接しています。
今、m個のグループの人達が座席に順番に座りに来ます。i番目(1≦i≦m)のグループの人数をa_i人とします。
彼らは、長テーブルに並んだ座席の内、ある連続するa_i個の座席に一斉に座ろうとします。
ただしお客さんは江戸っ子なので、それら座席のうち、いずれか一つでも既に先客に座られている座席があった場合、
一人も座らずにグループ全員で怒って帰ってしまいます。江戸っ子は気が早いんでぃ。
入力では、i番目のグループが座ろうとする連続した座席の位置は、整数b_iにより指定されます。
i番目のグループは、座席番号b_iの座席を始点として、そこから時計回りにa_i個分の座席に座ろうとします。
最後のグループが座りに来た後、無事に長テーブルの座席に着席出来ている人数を出力するプログラムを作成してください。
#入力
入力はm+1行から成ります。
1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
i+1行目(1≦i≦m)には2個の整数a_i(グループの人数)とb_i(着席開始座席番号)が半角スペース区切りで入力されます。
#出力
最後のグループが座りに来た後、無事に座席に着席出来ている人数を1行で出力してください。
#回答コード1(答にたどり着けない)
input_lines = gets.split(" ").map(&:to_i)
chairs=Array.new(input_lines[0] , false) #席数 falseデフォで座っている席をtrue
group = input_lines[1] #グループ数
group.times do
input = gets.split(" ").map(&:to_i)
f_chair=input[1]-1 #組み毎の先頭が座る席番 インデックスのため-1
cnt=input[0] #人数
if f_chair + cnt <= chairs.size then #座る席が0をまたぐか
next if chairs[f_chair , cnt].any? #座ろうとした席が一つでも埋まっていれば退出してしまう
chairs[f_chair,cnt].map{|c| c = true}
else
next if chairs[0 , (f_chair+cnt)%chairs.size].each{|c|c = true} || chairs[f_chair..-1].each{|c|c = true}
chairs[0 , (f_chair+cnt)%chairs.size].map{|c| c = true}
chairs[f_chair..-1].map{|c| c = true}
end
end
#答としてtrueの数を出力
##解説
上のコードで長い事躓いた
というのも
chairs[f_chair,cnt].map{|c| c = true}
この部分で、「着席済みの席はtrueに置き換える」としたいがchairsの値の置き換えが行われない
eachメソッドに置き換えてみたりデバック用のprint出力をちらばらせて確認しながらコードをかいてみたがどうにも
[false, false, false, false, false, false]
のまま処理が進んでしまう。
参考:https://teratail.com/questions/108200#
質問サイトに投げて解決。
”ある配列 ary のインデクス n の位置からm 個を 値 x で上書きする。”
勉強になりました。
#回答コード2(正答率100%)
input_lines = gets.split(" ").map(&:to_i)
group = input_lines[1] #組数
chairs=Array.new(input_lines[0] , false) #席数 falseデフォ
while(gets)
input = $_.split(" ").map(&:to_i)
cnt=input[0] #人数
f_chair=input[1]-1 #組毎の先頭が座る席番 インデックスのため-1
if f_chair + cnt <= chairs.size then #座る席が0をまたぐか
next if chairs[f_chair , cnt].any? #座ろうとした席が一つでも埋まっていれば退出してしまう
chairs[f_chair,cnt] = Array.new(cnt , true)
else #またぐ
sippo = (f_chair+cnt)%chairs.size
next if chairs[0 , sippo].any? || chairs[f_chair..-1].any?
chairs[0 , sippo] = Array.new(sippo , true)
chairs[f_chair..-1] = Array.new(cnt-sippo , true)
end
end
puts chairs.grep(true).size
##解説
この問題の頭を悩ます部分は(上のコードの書き方のミスで悩んだとは別)
1.席が円を描いている
2.客の座り方には最後の席番から0をまたいで何人か座る事も考えうる
ということ
参考:https://paiza.jp/learning/long-table?t=2fe1a138dcc3bbb167e6a97c7ff68672#editor-div
例に出すと26番から8名座ったりもすると言う事。
20から22名だったり。
なので
一つ目のif文でグループの一人目が座る席+グループ人数が席数を超えるときつまり0をまたいですわるか否か
それぞれの二つ目のif文で既に座っていたらnextでループをとばすようにしている。
sippo は席の最高値を超えている人数を表して応用した。