AOJ(問題集)9
AIZU ONLINE JUDGE: Programming Challenge
0081 A Symmetric Point
require 'matrix' $<.readlines.map {|l| l.split(",").map(&:to_f)}.each do |x1, y1, x2, y2, xq, yq| p1 = Vector[x1, y1] n = Vector[y2 - y1, x1 - x2].normalize q = Vector[xq, yq] d = (p1 - q).dot(n) r = q + (2 * d) * n printf "%.6f %.6f\n", r[0], r[1] end
わりとうまく解けた。
0082 Flying Jenny
table = [4, 1, 4, 1, 2, 1, 2, 1] $<.readlines.map {|l| l.split.map(&:to_i)}.each do |persons| result = (0..7).map do |i| order = table.rotate(i) left = persons.map.with_index do |n, j| a = n - order[j] a < 0 ? 0 : a end.sum [left, order] end.sort_by {|d| d.first} min = result.first.first result = result.select {|d| d.first == min}.sort_by {|d| d.last.join.to_i}.first puts result.last.join(" ") end
0083 Era Name Transformation
require 'date' table = [["pre-meiji", [ 1, 1, 1], [1868, 9, 7]], ["meiji" , [1868, 9, 8], [1912, 7, 29]], ["taisho" , [1912, 7, 30], [1926, 12, 24]], ["showa" , [1926, 12, 25], [1989, 1, 7]], ["heisei" , [1989, 1, 8], [2020, 1, 1]]] table.map! {|n, d1, d2| [n, Date.new(*d1), Date.new(*d2)]} $<.readlines.map {|l| Date.new(*l.split.map(&:to_i))}.each do |day| table.each do |name, d1, d2| if day.between?(d1, d2) if name == "pre-meiji" puts name else puts "#{name} #{day.year - d1.year + 1} #{day.month} #{day.day}" end end end end
0084 Search Engine
text = $<.gets.chomp puts text.split(/[ \.,]/).select {|w| w.length.between?(3, 6)}.join(" ")
0085 Joseph's Potato
until (a = $<.gets.split.map(&:to_i)) == [0, 0] n, m = a circle = [*1..n] try = ->(po) { return circle.first if circle.size == 1 po += m - 1 po -= circle.size while po >= circle.size circle = circle[0...po] + circle[po + 1..-1] try.(po) } puts try.(n) end
0086 Patrol
loop do roots = Hash.new([]) i = 0 loop do exit unless (l = io.gets) break if (l = l.split.map(&:to_i)) == [0, 0] a, b = l roots[a] += [[b, i]] roots[b] += [[a, i]] i += 1 end try = ->(spot, visited) { if spot == 2 return true if visited == 2 ** i - 1 else roots[spot].each do |nxt, root| next if (2 ** root & visited).nonzero? return true if try.(nxt, 2 ** root | visited) end end false } puts try.(1, 0) ? "OK" : "NG" end
これは時間オーバー。バックトラック法しか思いつかない。ちょっと他の人の回答を見たい。
例えばこの回答。
loop do spots = [] loop do line = $<.gets exit if line.nil? p0, p1 = line.chomp.split(" ").map(&:to_i) break if p0.zero? and p1.zero? p0 -= 1 p1 -= 1 spots[p0] = spots[p0] ? (spots[p0] + 1) : 1 spots[p1] = spots[p1] ? (spots[p1] + 1) : 1 end #p spots ok = true if spots[0].even? or spots[1].even? ok = false else (2...spots.length).each do |i| if spots[i].odd? ok = false break end end end puts ok ? "OK" : "NG" end
これは…、瞬殺である。配列 spots はその場所から出ている道の数を表わしている。
なるほど、道が一筆書きになればよいわけだな。そんな簡単なことに気づかなかったとは!
0087 Strange Mathematical Expression
$<.readlines.map {|l| l.chomp.split}.each do |data| stack = [] while (x = data.shift) if %w(+ - * /).include?(x) a, b = stack.pop, stack.pop stack << eval("#{b}.to_f #{x} #{a}") else stack << x end end printf "%.6f\n", stack.first end
0088 The Code A Doctor Loved
table1 = {"'"=>"000000", ","=>"000011", "-"=>"10010001", "."=>"010001", "?"=>"000001", "A"=>"100101", "B"=>"10011010", "C"=>"0101", "D"=>"0001", "E"=>"110", "F"=>"01001", "G"=>"10011011", "H"=>"010000", "I"=>"0111", "J"=>"10011000", "K"=>"0110", "L"=>"00100", "M"=>"10011001", "N"=>"10011110", "O"=>"00101", "P"=>"111", "Q"=>"10011111", "R"=>"1000", "S"=>"00110", "T"=>"00111", "U"=>"10011100", "V"=>"10011101", "W"=>"000010", "X"=>"10010010", "Y"=>"10010011", "Z"=>"10010000", " "=>"101"} table2 = {"00000"=>"A", "00001"=>"B", "00010"=>"C", "00011"=>"D", "00100"=>"E", "00101"=>"F", "00110"=>"G", "00111"=>"H", "01000"=>"I", "01001"=>"J", "01010"=>"K", "01011"=>"L", "01100"=>"M", "01101"=>"N", "01110"=>"O", "01111"=>"P", "10000"=>"Q", "10001"=>"R", "10010"=>"S", "10011"=>"T", "10100"=>"U", "10101"=>"V", "10110"=>"W", "10111"=>"X", "11000"=>"Y", "11001"=>"Z", "11010"=>" ", "11011"=>".", "11100"=>",", "11101"=>"-", "11110"=>"'", "11111"=>"?"} $<.readlines.each do |line| line.chomp! text = "" line.each_char {|c| text += table1[c]} l = text.length % 5 text += "0" * (5 - l) if l > 0 result = "" until text.empty? result += table2[text[0, 5]] text = text[5..-1] end puts result end
0089 The Shortest Path on A Rhombic Path
lines = $<.readlines.map {|l| l.split(",").map(&:to_i)} ln = lines.size / 2 + 1 up = ->(n, sums) { return sums if n == ln nxt = Array.new(n + 1, 0) sums.each_index do |i| nxt[i] = sums[i] + lines[n][i] if i.zero? nxt[i + 1] = sums[i, 2].max + lines[n][i + 1] end up.(n + 1, nxt) } mid = up.(1, lines.first) down = ->(n, sums) { return sums.first if sums.size == 1 nxt = sums.each_cons(2).map.with_index do |pair, i| lines[n][i] + pair.max end down.(n + 1, nxt) } puts down.(ln, mid)
こんな面倒なやり方しか思いつかなかった。むずかしかったので一発でいってよかった。ダメだったら考え直す気力がない…。
0090 Overlaps of Seals
全然思いつかない…。他人の回答を見る(自己流に改変しています)。
require 'matrix' DELTA = 1e-6 until (n = $<.gets.to_i).zero? points = [] n.times do points << Vector[*$<.gets.chomp.split(",").map(&:to_f)] end cps = [] points.each_with_index do |p0, i| (i + 1...n).each do |j| p1 = points[j] v = p1 - p0 d = v.norm if d <= 1.0 + DELTA hd = d / 2 ul = Math.sqrt(1.0 - hd * hd) u = Vector[-v[1], v[0]] / d * ul c = (p0 + p1) / 2 cps << c + u cps << c - u end end end max_ov = 1 cps.each do |cp| ov = 0 points.each do |point| ov += 1 if (point - cp).norm <= 1.0 + DELTA end max_ov = ov if max_ov < ov end puts max_ov end