AOJ(問題集)20
AIZU ONLINE JUDGE: Programming Challenge
0190 Eleven Puzzle
素直に幅優先探索を実行して死んだので、ここを参考に解いた。「両側探索」というらしい。
start = "fff0fff" "ff123ff" "f45678f" "ff9abff" "fff0fff" result1 = {} result1[start] = 0 stack = [start] # 一方からの探索 while (nxt = stack.shift) next if result1[nxt] >= 10 doit1 = ->(idx) { [1, -1, 7, -7].each do |di| next_index = idx + di next if next_index < 0 or next_index >= 35 next if (c = nxt[next_index]) == "f" or c == "0" next_field = nxt.dup next_field[idx] = c next_field[next_index] = "0" next if result1[next_field] result1[next_field] = result1[nxt] + 1 stack << next_field end } doit1.(nxt.index("0")) doit1.(nxt.rindex("0")) end # 反対側からの探索 pat = Array.new(5) until (pat[0] = gets.to_i) == -1 pat[0] = pat[0].to_s(16).center(7, "f") 4.times {|i| pat[i + 1] = gets.split.map {|a| a.to_i.to_s(16)}.join.center(7, "f") } if (ans = result1[start = pat.join]) puts ans next end result2 = {} result2[start] = 0 stack = [start] str = "NA" f = true while (nxt = stack.shift) and f next if result2[nxt] >= 10 doit2 = ->(idx) { [1, -1, 7, -7].each do |di| next_index = idx + di next if next_index < 0 or next_index >= 35 next if (c = nxt[next_index]) == "f" or c == "0" next_field = nxt.dup next_field[idx] = c next_field[next_index] = "0" next if result2[next_field] if result1[next_field] str = (result1[next_field] + result2[nxt] + 1).to_s return false end result2[next_field] = result2[nxt] + 1 stack << next_field end true } f = doit2.(nxt.index("0")) f = doit2.(nxt.rindex("0")) if f end puts str end
0191 Baby Tree
until (given = gets.split.map(&:to_i)) == [0, 0] n, m = given g = n.times.map {gets.split.map(&:to_f)} memo = Array.new(101) {Array.new(101)} compost = ->(num, left) { return memo[num][left] if memo[num][left] memo[num][left] = if left.zero? 1.0 else n.times.map {|j| g[num][j] * compost.(j, left - 1)}.max end } printf "%.02f\n", n.times.map {|i| compost.(i, m - 1)}.max.round(2) end
アホなミスをしていた。メモ化で値が存在するときに return を忘れているという…(笑)
0192 Multistory Parking Lot
class Car num = 1 define_method(:initialize) do |waiting_time| @num = num num += 1 @time = waiting_time end attr_reader :num attr_accessor :time define_singleton_method(:clear) {num = 1} end class ParkingLot Space = Struct.new(:upper, :lower) def initialize(num) @spaces = num.times.map {|i| Space.new} end def add_car(waiting_time) idx = @spaces.index {|sp| sp.lower.nil?} if idx @spaces[idx].lower = Car.new(waiting_time) #下のスペースが空いている else return false if @spaces.all?(&:upper) #満車 #下は空いていないが満車でない場合 idxs = @spaces.map.with_index {|sp, i| i unless sp.upper}.compact idx = idxs.map do |i| diff = @spaces[i].lower.time - waiting_time diff >= 0 ? [diff, i] : nil end.compact.sort.first&.last unless idx idx = idxs.map {|i| [waiting_time - @spaces[i].lower.time, i]}.sort.first.last end @spaces[idx].upper = @spaces[idx].lower @spaces[idx].lower = Car.new(waiting_time) end true end def next @spaces.each do |sp| if sp.lower sp.lower.time -= 1 sp.upper.time -= 1 if sp.upper end end out = [] 2.times do @spaces.each do |sp| if sp.lower and sp.lower.time <= 0 out << sp.lower.num sp.lower = sp.upper sp.upper = nil end end end out end #車庫が空か def empty? @spaces.all? {|sp| sp.lower.nil?} end end until (given = gets.split.map(&:to_i)) == [0, 0] m, n = given parking_time = n.times.map {gets.to_i} pl = ParkingLot.new(m) result = [] wait = [] Car.clear t = 0 loop do result += pl.next wait << parking_time.shift if (t % 10).zero? t += 1 while (wait_time = wait.shift) unless pl.add_car(wait_time) wait.unshift(wait_time) #満車の場合 break end end break if pl.empty? end puts result.join(" ") end
だいぶ勘違いをしていた。Ruby では三人しか出来ていないですよ。
0194 Delivery Company
MaxTime = 100 Truck = Struct.new(:x, :y, :dir, :time) def get_hv(str) h, v = str.split("-") [h.bytes.first - 97, v.to_i - 1] end def signal_wait(x, y, signals, next_dir, time) signal = false movable = true signals.each do |hv, k| if x == hv[1] && y == hv[0] signal = true if (i = time / k).odd? #東西方向が青? movable = false if next_dir.odd? else movable = false if next_dir.even? end end end [movable, signal] end def under_construction?(stat, x, y, constructions) constructions.each do |hv1, hv2| return true if stat.x == hv1[1] && stat.y == hv1[0] && x == hv2[1] && y == hv2[0] return true if stat.x == hv2[1] && stat.y == hv2[0] && x == hv1[1] && y == hv1[0] end false end def add_holdup(stat, x, y, holdups) next_time = stat.time holdups.each do |hv1, hv2, d| f1 = (stat.x == hv1[1] && stat.y == hv1[0] && x == hv2[1] && y == hv2[0]) f2 = (stat.x == hv2[1] && stat.y == hv2[0] && x == hv1[1] && y == hv1[0]) next_time += d if f1 || f2 end next_time end until (mn = gets.split.map(&:to_i)) == [0, 0] d0 = gets.to_i signals = gets.to_i.times.map do hv, k = gets.chomp.split [get_hv(hv), k.to_i] end constructions = gets.to_i.times.map do hv1, hv2 = gets.chomp.split [get_hv(hv1), get_hv(hv2)] end holdups = gets.to_i.times.map do hv1, hv2, d = gets.chomp.split [get_hv(hv1), get_hv(hv2), d.to_i] end start, goal = gets.split.map {|hv| get_hv(hv)} field = Array.new(mn[0]) {Array.new(mn[1])} queue = [Truck.new(start[1], start[0], 0, 0)] field[start[0]][start[1]] = queue.first min_time = Float::INFINITY go = ->(stat, dir) { next_dir = (stat.dir + dir) % 4 dx, dy = [[1, 0], [0, -1], [-1, 0], [0, 1]][next_dir] x = stat.x + dx y = stat.y + dy return [] if x < 0 || x >= mn[1] || y < 0 || y >= mn[0] return [] if under_construction?(stat, x, y, constructions) next_time = d0 + add_holdup(stat, x, y, holdups) movable, signal = signal_wait(x, y, signals, next_dir, next_time) return [] unless movable return [] if next_time > MaxTime next_stat = Truck.new(x, y, next_dir, next_time) tmp = field[y][x] return [next_stat] if signal if tmp return [] if tmp.time <= next_time end [field[y][x] = next_stat] } while (now = queue.shift) if now.x == goal[1] && now.y == goal[0] min_time = now.time if min_time > now.time else queue += go.(now, 0) queue += go.(now, 1) queue += go.(now, -1) end end puts min_time end
10秒で時間オーバー。
0195 What is the Most Popular Shop in Tokaichi?
Shop = "ABCDE" N = Shop.length until (data = [gets.chomp]) == ["0 0"] data.concat (N - 1).times.map {gets} result = data.map.with_index {|d, i| [d.split.map(&:to_i).sum, i]}.sort.last puts "#{Shop[result[1]]} #{result[0]}" end
0196 Baseball Championship
until (n = gets.to_i).zero? data = n.times.map {gets.chomp.split} scores = data.map {|n, *r| [n, r.count("0"), r.count("1")]} .sort {|a, b| (b[1] <=> a[1]).nonzero? || a[2] <=> b[2]} puts scores.map(&:first) end
複数キーのソート。
0197 Greatest Common Divisor: Euclidean Algorithm
until (given = gets.chomp) == "0 0" x, y = given.split.map(&:to_i) x, y = y, x if x < y count = 0 until y.zero? x = x % y x, y = y, x count += 1 end puts "#{x} #{count}" end
0198 Trouble in Shinagawa's Artifacts
table = [[0, 1, 2, 3, 4, 5], [3, 1, 0, 5, 4, 2], [1, 5, 2, 3, 0, 4], [4, 0, 2, 3, 5, 1], [2, 1, 5, 0, 4, 3], [0, 2, 4, 1, 3, 5], [0, 3, 1, 4, 2, 5], [5, 1, 3, 2, 4, 0], [1, 2, 0, 5, 3, 4], [4, 3, 0, 5, 2, 1], [3, 0, 4, 1, 5, 2], [3, 5, 1, 4, 0, 2], [5, 4, 2, 3, 1, 0], [2, 5, 4, 1, 0, 3], [1, 3, 5, 0, 2, 4], [2, 0, 1, 4, 5, 3], [4, 2, 5, 0, 3, 1], [0, 4, 3, 2, 1, 5], [1, 0, 3, 2, 5, 4], [4, 5, 3, 2, 0, 1], [5, 3, 4, 1, 2, 0], [5, 2, 1, 4, 3, 0], [2, 4, 0, 5, 1, 3], [3, 4, 5, 0, 1, 2]] color_table = %w(Red Yellow Blue Magenta Green Cyan).map .with_index {|c, i| [c, i]}.to_h until (n = gets.to_i).zero? dices = n.times.map { gets.split.map {|c_name| color_table[c_name]} } pool = [] count = 0 dices.each do |color| check_f = true table.each do |t| next_dice = t.map {|idx| color[idx]} if pool.include?(next_dice) count += 1 if check_f check_f = false else pool << next_dice end end end puts count end
0199 Chairs Where Demanding People Sit
def a(seats) seats[seats.index("#")] = "A" end def b(seats, n) (n - 1).downto(0) do |i| if (i - 1 < 0 || seats[i - 1] != "A") && seats[i + 1] != "A" && seats[i] == "#" seats[i] = "B" return end end seats[seats.index("#")] = "B" end def c(seats, n) if seats.count("#") == n idx = n / 2 else n.times do |i| if seats[i] != "#" if seats[i + 1] == "#" idx = i + 1 break elsif i - 1 >= 0 && seats[i - 1] == "#" idx = i - 1 break end end end end seats[idx] = "C" end def d(seats, n) idx = 0 if seats.count("#") != n max_dist = 0 n.times do |i| d = nearest_dist(seats, i) if d > max_dist max_dist = d idx = i end end end seats[idx] = "D" end def nearest_dist(seats, i) dist = 0 dist += 1 until /[A-D]/ =~ seats[i + dist] || (i - dist >= 0 && /[A-D]/ =~ seats[i - dist]) dist end until (given = gets.split.map(&:to_i)) == [0, 0] n, m = given seats = "#" * n m.times do case gets.chomp when "A" then a(seats) when "B" then b(seats, n) when "C" then c(seats, n) when "D" then d(seats, n) end end puts seats end