AOJ(問題集)14

AIZU ONLINE JUDGE: Programming Challenge
 

0130 Train

$<.gets.to_i.times do
  given = $<.gets.chomp.split(/(->|<-)/)
  train = [given.shift]
  while (dir = given.shift)
    car = given.shift
    next if train.include?(car)
    (dir == "->") ? train.push(car) : train.unshift(car)
  end
  puts train.join
end

出来てみればじつに簡単なことなのに、ものすごく悩んだ。
 

0131 Doctor's Strange Particles

L = 10

$<.gets.to_i.times do
  field = Array.new(L) {$<.gets.split.map(&:to_i)}.flatten
  result = Array.new(L * L, 0)
  
  reverse = ->(x, y) {
    [[0, 0], [1, 0], [0, -1], [-1, 0], [0, 1]].each do |dx, dy|
      x1 = x + dx
      y1 = y + dy
      next if x1 < 0 or x1 >= L or y1 < 0 or y1 >= L
      i = y1 * L + x1
      field[i] = 1 - field[i]
    end
  }
  
  top_row = ->(i) {
    if i >= L
      tmp1 = field.dup
      tmp2 = result.dup
      while i < L * L
        if field[i - L] == 1
          result[i] = 1
          reverse.(i % L, i / L)
        end
        i += 1
      end
      if field.all? {|i| i.zero?}
        puts result.each_slice(L).map {|a| a.join(" ")}
        true
      else
        field  = tmp1
        result = tmp2
        false
      end
    else
      return true if top_row.(i + 1)
      
      result[i] = 1
      reverse.(i % L, i / L)
      return true if top_row.(i + 1)
      reverse.(i % L, i / L)
      result[i] = 0
      false
    end
  }
  top_row.(0)
end

些細なミスが多かった。
 

0132 Jigsaw Puzzle

until (a = $<.gets.split.map(&:to_i)) == [0, 0]
  h, w = a
  puzzle = h.times.map {$<.gets.chomp}
  pieces = $<.gets.to_i.times.flat_map do
    ph, pw = $<.gets.split.map(&:to_i)
    tmp = [ph.times.map {$<.gets.chomp}]
    3.times do
      tmp << tmp.last.reverse.map(&:chars).transpose.map(&:join)
    end
    tmp
  end
  
  $<.gets.to_i.times do
    k, *tn = $<.gets.split.map(&:to_i)
    tn = tn.map {|i| i - 1}.sort
    tn1 = tn.flat_map {|i| 4.times.map {|j| i * 4 + j}}.sort
    
    solve = ->(embeded, selected = [], selected_num = []) {
      return true if !embeded.join.index(".") and tn == selected_num
      
      adjust = ->(piece, piece_num) {
        idx = embeded.join.index(".")
        return false unless idx
        x, y = idx % w, idx / w
        
        p_idx = piece.join.index("#")
        pw = piece.first.length
        px = p_idx % pw
        return false if x + pw - px >= w
        return false if (x -= px) < 0
        
        nxt = embeded.map(&:dup)
        piece.each_index do |i|
          piece[i].each_char.with_index do |c, j|
            if c == "#"
              if embeded[y + i][x + j] == "."
                nxt[y + i][x + j] = (piece_num / 4).to_s
              else
                return false
              end
            end
          end
        end
        nxt
      }
      
      (tn1 - selected).each do |pn|
        next unless selected.select {|i| i / 4 == pn / 4}.empty?
        if (nxt = adjust.(pieces[pn], pn))
          return true if solve.(nxt, selected + [pn], (selected_num + [pn / 4]).sort)
        end
      end
      false
    }
    puts solve.(puzzle) ? "YES" : "NO"
  end
end

時間オーバー。

until (a = $<.gets.split.map(&:to_i)) == [0, 0]
  h, w = a
  puzzle = h.times.map {$<.gets.chomp}
  pieces = (n = $<.gets.to_i).times.map do
    ph, pw = $<.gets.split.map(&:to_i)
    ph.times.map {$<.gets.chomp}
  end
  
  io.gets.to_i.times do
    k, *tn = $<.gets.split.map(&:to_i)
    tn = tn.map {|i| i - 1}.sort
    
    solve = ->(embeded, selected = []) {
      return true if !embeded.join.index(".") and tn == selected
      
      adjust = ->(piece) {
        idx = embeded.join.index(".")
        return false unless idx
        x, y = idx % w, idx / w
        
        p_idx = piece.join.index("#")
        pw = piece.first.length
        px = p_idx % pw
        return false if x + pw - px >= w
        return false if (x -= px) < 0
        
        nxt = embeded.map(&:dup)
        piece.each_index do |i|
          piece[i].each_char.with_index do |c, j|
            if c == "#"
              if embeded[y + i][x + j] == "."
                nxt[y + i][x + j] = "#"
              else
                return false
              end
            end
          end
        end
        nxt
      }
      check = ->(piece_num) {
        candidate = pieces[piece_num]
        nexts = []
        4.times do
          if (nxt = adjust.(candidate))
            nexts << nxt
          end
          candidate = candidate.reverse.map(&:chars).transpose.map(&:join)
        end
        nexts.empty? ? false : nexts
      }
      
      (tn - selected).each do |piece_num|
        if (nexts = check.(piece_num))
          nexts.each do |nxt|
            return true if solve.(nxt, (selected + [piece_num]).sort)
          end
        end
      end
      false
    }
    puts solve.(puzzle) ? "YES" : "NO"
  end
end

上も下もやり方は合っていると思うけれど、時間オーバー。Ruby では誰も解けていない。
 

0133 Rotation of a Pattern

given = $<.readlines.map(&:chomp)
3.times do |i|
  puts 90 * (i + 1)
  puts given = given.reverse.map(&:chars).transpose.map(&:join)
end

突然簡単に。
 

0134 Exit Survey

n = $<.gets.to_i
puts Array.new(n) {$<.gets.to_i}.sum / n

 

0135 Clock Short Hand and Long Hand

$<.gets.to_i.times do
  h, m = $<.gets.split(":").map(&:to_r)
  l, s = m * 6, (h * 60 + m) / 2
  r = (l - s).abs
  r = 360 - r if r > 180
  st = if 0 <= r and r < 30
    "alert"
  elsif 90 <= r and r <= 180
    "safe"
  else
    "warning"
  end
  puts st
end

 

0136 Frequency Distribution of Height

度数分布。

L = 6
table = 165.0.step(185.0, 5.0).each_cons(2).to_a 
table = [[0, 165.0]] + table + [[185.0, Float::INFINITY]]
count = Array.new(L, 0)

$<.gets.to_i.times do
  h = $<.gets.to_f
  count[table.index {|a, b| a <= h and h < b}] += 1
end

count.each_with_index {|i, j| puts "#{j + 1}:" + "*" * i}

 

0137 Middle-Square Method

平方採中法。

$<.gets.to_i.times do |i|
  num = $<.gets.to_i
  rnd = Enumerator.new do |y|
    loop do
      num = (num * num).to_s.rjust(8, "0")[2, 4].to_i
      y << num
    end
  end
  puts "Case #{i + 1}:"
  puts rnd.take(10)
end

Ruby っぽいコードだと思います。Enumerator にぴったりな問題というのはあまりない気がする。
 

0138 Track and Field Competition

get = ->{ Array.new(8) {$<.gets.chomp.split} }

left = 3.times.flat_map do
  given = get.().sort_by {|a| a.last.to_f}
  puts given.shift.join(" ")
  puts given.shift.join(" ")
  given
end.sort_by {|a| a.last.to_f}
puts left.shift.join(" ")
puts left.shift.join(" ")

 

0139 Snakes

$<.gets
$<.readlines.map(&:chomp).each do |line|
  s1 = /^>'(=+)#(=+)~$/.match(line)
  s2 = /^>\^(Q=)+~~$/.match(line)
  str = if s1 and s1[1] == s1[2]
    "A"
  elsif s2
    "B"
  else
    "NA"
  end
  puts str
end

正規表現を使うのはめずらしい。