AOJ (Introduction to Programming)
AIZU ONLINE JUDGE: Programming Challenge
ITP1_1_A
puts "Hello World"
ITP1_1_B
x = gets.to_i
puts x ** 3
ITP1_1_C
a, b = gets.split.map(&:to_i) puts "#{a * b} #{2 * (a + b)}"
ITP1_1_D
n = gets.to_i puts "#{n / 3600}:#{(n % 3600) / 60}:#{n % 60}"
ITP1_2_A
a, b = gets.split.map(&:to_i) st = if a < b then "<" elsif a > b then ">" else "==" end puts "a #{st} b"
ITP1_2_B
a, b, c = gets.split.map(&:to_i) puts (a < b and b < c) ? "Yes" : "No"
ITP1_2_C
puts gets.split.map(&:to_i).sort.join(" ")
ITP1_2_D
w, h, x, y, r = gets.split.map(&:to_i) st = if x - r >= 0 and y - r >= 0 and x + r <= w and y + r <= h "Yes" else "No" end puts st
ITP1_3_A
1000.times {puts "Hello World"}
IPT1_3_B
i = 0 until (x = gets.to_i).zero? puts "Case #{i += 1}: #{x}" end
ITP1_3_C
loop do x, y = gets.split.map(&:to_i).sort break if x.zero? and y.zero? puts "#{x} #{y}" end
ITP1_3_D
a, b, c = gets.split.map(&:to_i) cnt = 0 a.upto(b) {|i| cnt += 1 if (c % i).zero?} puts cnt
ITP1_4_A
a, b = gets.split.map(&:to_i) printf "%d %d %.5f", a / b, a % b, a.to_f / b
ITP1_4_B
r = gets.to_f pi = Math::PI printf "%.6f %.6f", pi * r ** 2, 2 * pi * r
ITP1_4_C
until /\d+ \? \d+/.match(st = gets) puts eval(st) end
ITP1_4_D
gets a = gets.split.map(&:to_i) puts "#{a.min} #{a.max} #{a.inject(&:+)}"
ITP1_5_A
loop do h, w = gets.split.map(&:to_i) break if h.zero? and w.zero? h.times {puts "#" * w} puts end
ITP1_5_B
loop do h, w = gets.split.map(&:to_i) break if h.zero? and w.zero? st = "#" * w puts st (h - 2).times {puts "#" + "." * (w - 2) + "#"} puts st puts end
ITP1_5_C
loop do h, w = gets.split.map(&:to_i) break if h.zero? and w.zero? st1 = ("#." * w)[0, w] st2 = ("." + st1)[0, w] h.times {|i| puts [st1, st2][i % 2]} puts end
ITP1_5_D
n = gets.to_i i = 1 while i <= n x = i if (x % 3).zero? print " #{i}" else until x.zero? if x % 10 == 3 print " #{i}" break else x /= 10 end end end i += 1 end puts
ITP1_6_A
gets puts gets.split.reverse.join(" ")
ITP1_6_B
n = gets.to_i cards = [] %W(S H C D).each do |suit| 1.upto(13) {|i| cards << "#{suit} #{i}"} end n.times {cards -= [gets.chomp]} puts cards
ITP1_6_C
n = gets.to_i rooms = Array.new(4) {Array.new(3) {Array.new(10, 0)}} n.times do b, f, r, v = gets.split.map(&:to_i) rooms[b - 1][f - 1][r - 1] += v end st = Array.new(4, "") 4.times do |b| 3.times do |f| 10.times do |r| st[b] += " " + rooms[b][f][r].to_s end st[b] += "\n" end end print st.join("#" * 20 + "\n")
ITP1_6_D
n, m = gets.split.map(&:to_i) a, c = [], [] n.times {a << gets.split.map(&:to_i)} m.times {c << gets.to_i} n.times do |i| sum = 0 m.times {|j| sum += a[i][j] * c[j]} puts sum end
ITP1_7_A
loop do m, f, r = gets.split.map(&:to_i) break if m == -1 and f == -1 and r == -1 sum = m + f st = if m == -1 or f == -1 "F" elsif sum >= 80 "A" elsif sum >= 65 "B" elsif sum >= 50 "C" elsif sum >= 30 (r >= 50) ? "C" : "D" else "F" end puts st end
ITP1_7_B
loop do n, x = gets.split.map(&:to_i) break if n.zero? and x.zero? cnt = 0 [*1..n].combination(3) do |ar| cnt += 1 if ar[0] + ar[1] + ar[2] == x end puts cnt end
ITP1_7_C
r, c = gets.split.map(&:to_i) m = [] r.times {m << gets.split.map(&:to_i)} tate = Array.new(c, 0) putout = ->(ar) { st = "" sum = 0 ar.each_with_index do |x, i| st += x.to_s + " " sum += x tate[i] += x end st += sum.to_s puts st } m.each {|x| putout.(x)} putout.(tate)
ITP1_7_D
n, m, l = gets.split.map(&:to_i) a, b = [], [] n.times {a << gets.split.map(&:to_i)} m.times {b << gets.split.map(&:to_i)} a.each do |row| c = Array.new(l, 0) row.each_with_index do |x, i| l.times {|j| c[j] += x * b[i][j]} end puts c.join(" ") end
ITP1_8_A
st = "" gets.chomp.each_byte do |byte| st += if byte.between?(97, 122) (byte - 32).chr elsif byte.between?(65, 90) (byte + 32).chr else byte.chr end end puts st
ITP1_8_B
loop do x = gets.chomp break if x == "0" puts x.chars.map(&:to_i).inject(&:+) end
ITP1_8_C
result = Array.new(26, 0) $stdin.readlines.map(&:chomp).join.downcase.each_byte do |byte| next unless byte.between?(97, 122) result[byte - 97] += 1 end result.each_with_index {|x, i| puts "#{(i + 97).chr} : #{x}"}
ITP1_8_D
s, p = gets.chomp, gets.chomp ring = s + s l = p.length result = "No" s.length.times do |i| if ring[i, l] == p result = "Yes" break end end puts result
ITP1_9_A
w = gets.chomp t = "" loop do st = gets.chomp break if st == "END_OF_TEXT" t += st.downcase + " " end puts t.split.count(w)
ITP1_9_B
loop do deck = gets.chomp break if deck == "-" gets.to_i.times do i = gets.to_i deck = deck[i..-1] + deck[0, i] end puts deck end
ITP1_9_C
taro = hanako = 0 gets.to_i.times do t, h = gets.chomp.split if t > h taro += 3 elsif t < h hanako += 3 else taro += 1 hanako += 1 end end puts "#{taro} #{hanako}"
ITP1_9_D
str = gets.chomp gets.to_i.times do command = gets.split a = command[1].to_i b = command[2].to_i case command[0] when "print" puts str[a..b] when "reverse" str = str[0, a] + str[a..b].reverse + str[b + 1..-1] when "replace" str = str[0, a] + command[3] + str[b + 1..-1] end end
ITP1_10_A
x1, y1, x2, y2 = gets.split.map(&:to_f) puts Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
ITP1_10_B
include Math a, b, c = gets.split.map(&:to_i) θ = c / 180.0 * PI h = b * sin(θ) puts a * h / 2 puts a + b + sqrt(a ** 2 + b ** 2 - 2 * a * b * cos(θ)) puts h
ITP1_10_C
#標準偏差 loop do n = gets.to_i break if n.zero? s = gets.split.map(&:to_i) m = s.inject(&:+) / n.to_f sum = 0 s.each {|i| sum += (i - m) ** 2} puts Math.sqrt(sum / n) end
ITP1_10_D
n = gets.to_i x = gets.split.map(&:to_i) y = gets.split.map(&:to_i) d = ->(p) { sum = 0 n.times {|i| sum += (x[i] - y[i]).abs ** p} sum ** (1 / p.to_f) } 1.upto(3) {|i| puts d.(i)} puts x.zip(y).map {|x, y| (x - y).abs.to_f}.max
ITP1_11_A
dice = gets.split.map(&:to_i) commands = gets.chomp.chars.map(&:to_sym) throw = {E: [3, 2, 6, 1, 5, 4], N: [5, 1, 3, 4, 6, 2], S: [2, 6, 3, 4, 1, 5], W: [4, 2, 1, 6, 5, 3]} th = {} throw.each_key {|k| th[k] = throw[k].map(&:pred)} commands.each do |c| next_dice = Array.new(6, 0) dice.each_with_index do |d, i| next_dice[th[c][i]] = d end dice = next_dice end puts dice[0]
ITP1_11_B
possible_appearances = ->(dice) { table = [[0, 1, 2, 3, 4, 5], [3, 1, 0, 5, 4, 2], [1, 5, 2, 3, 0, 4], [5, 1, 3, 2, 4, 0], [1, 2, 0, 5, 3, 4], [3, 5, 1, 4, 0, 2], [5, 4, 2, 3, 1, 0], [2, 1, 5, 0, 4, 3], [1, 0, 3, 2, 5, 4], [5, 2, 1, 4, 3, 0], [2, 4, 0, 5, 1, 3], [4, 5, 3, 2, 0, 1], [3, 4, 5, 0, 1, 2], [4, 0, 2, 3, 5, 1], [1, 3, 5, 0, 2, 4], [2, 0, 1, 4, 5, 3], [0, 4, 3, 2, 1, 5], [4, 2, 5, 0, 3, 1], [4, 3, 0, 5, 2, 1], [2, 5, 4, 1, 0, 3], [3, 0, 4, 1, 5, 2], [0, 3, 1, 4, 2, 5], [0, 2, 4, 1, 3, 5], [5, 3, 4, 1, 2, 0]] result = [] table.each do |dice1| another = Array.new(6, 0) dice1.each_with_index {|n, i| another[n] = dice[i]} result << another end result.uniq } appearances = possible_appearances.(gets.split.map(&:to_i)) gets.to_i.times do top, front = gets.split.map(&:to_i) appearances.each do |a| if a[0] == top and a[1] == front puts a[2] break end end end
ITP1_11_C
possible_appearances = ->(dice) { table = [[0, 1, 2, 3, 4, 5], [3, 1, 0, 5, 4, 2], [1, 5, 2, 3, 0, 4], [5, 1, 3, 2, 4, 0], [1, 2, 0, 5, 3, 4], [3, 5, 1, 4, 0, 2], [5, 4, 2, 3, 1, 0], [2, 1, 5, 0, 4, 3], [1, 0, 3, 2, 5, 4], [5, 2, 1, 4, 3, 0], [2, 4, 0, 5, 1, 3], [4, 5, 3, 2, 0, 1], [3, 4, 5, 0, 1, 2], [4, 0, 2, 3, 5, 1], [1, 3, 5, 0, 2, 4], [2, 0, 1, 4, 5, 3], [0, 4, 3, 2, 1, 5], [4, 2, 5, 0, 3, 1], [4, 3, 0, 5, 2, 1], [2, 5, 4, 1, 0, 3], [3, 0, 4, 1, 5, 2], [0, 3, 1, 4, 2, 5], [0, 2, 4, 1, 3, 5], [5, 3, 4, 1, 2, 0]] result = [] table.each do |dice1| another = Array.new(6, 0) dice1.each_with_index {|n, i| another[n] = dice[i]} result << another end result.uniq } dice1 = gets.split.map(&:to_i) dice2 = gets.split.map(&:to_i) puts possible_appearances.(dice1).include?(dice2) ? "Yes" : "No"
ITP1_11_D
possible_appearances = ->(dice) { table = [[0, 1, 2, 3, 4, 5], [3, 1, 0, 5, 4, 2], [1, 5, 2, 3, 0, 4], [5, 1, 3, 2, 4, 0], [1, 2, 0, 5, 3, 4], [3, 5, 1, 4, 0, 2], [5, 4, 2, 3, 1, 0], [2, 1, 5, 0, 4, 3], [1, 0, 3, 2, 5, 4], [5, 2, 1, 4, 3, 0], [2, 4, 0, 5, 1, 3], [4, 5, 3, 2, 0, 1], [3, 4, 5, 0, 1, 2], [4, 0, 2, 3, 5, 1], [1, 3, 5, 0, 2, 4], [2, 0, 1, 4, 5, 3], [0, 4, 3, 2, 1, 5], [4, 2, 5, 0, 3, 1], [4, 3, 0, 5, 2, 1], [2, 5, 4, 1, 0, 3], [3, 0, 4, 1, 5, 2], [0, 3, 1, 4, 2, 5], [0, 2, 4, 1, 3, 5], [5, 3, 4, 1, 2, 0]] result = [] table.each do |dice1| another = Array.new(6, 0) dice1.each_with_index {|n, i| another[n] = dice[i]} result << another end result.uniq } solve = ->(dices) { s = dices.size (s - 1).times do |i| appearances = possible_appearances.(dices[i]) (i + 1).upto(s - 1) do |j| return "No" if appearances.include?(dices[j]) end end "Yes" } n = gets.to_i dices = [] n.times {dices << gets.split.map(&:to_i)} puts solve.(dices)
tty で日本語を表示する
fbterm を入れる。
$ sudo apt install fbterm
tty で次を実行。
$ sudo fbterm
ただしこのままだとフォントサイズが小さくて見にくいかも知れない。そのときは ~/.fbtermrc を編集する(Ubuntuの場合)。
font-names=Ubuntu mono font-size=20
とかいう感じ。
パスカルの三角形(Haskell)
その1。
main :: IO () main = print $ map pascal [0..8] pascal :: Int -> [Int] pascal 0 = [1] pascal n = [1] ++ eachCons (pascal (n - 1)) ++ [1] eachCons :: [Int] -> [Int] eachCons xs = if length xs < 2 then [] else (head xs + (head . tail) xs): (eachCons . tail) xs
結果。
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1],[1,6,15,20,15,6,1],[1,7,21,35,35,21,7,1],[1,8,28,56,70,56,28,8,1]]
その2。
main :: IO () main = putStr $ unlines $ map (centering 30 . toString) (map pascal [0..8]) centering :: Int -> String -> String centering n str = (replicate i ' ') ++ str ++ (replicate j ' ') where l = length str i = div (n - l) 2 j = n - l - i toString :: [Int] -> String toString xs = tail $ concat $ map f xs where f x = ' ': show x pascal :: Int -> [Int] pascal 0 = [1] pascal n = [1] ++ eachCons (pascal (n - 1)) ++ [1] eachCons :: [Int] -> [Int] eachCons xs = if length xs < 2 then [] else (head xs + (head . tail) xs): (eachCons . tail) xs
結果。
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1
unlines 関数:[String]を改行を入れて結合する。[String] -> String。
concat 関数:リストの平坦化。
div 関数:整数/整数をして整数で返す。
elementary OS 0.4.1 Loki をインストール
インストール・ファイルはここからダウンロードします。「価格はあなた次第」とありますので、お金を払ってもよいという人は手続きして下さい。無料で使いたい場合は「カスタム」を選択し、0 を入力してインストールすればいいです。
インストールそのものは Debian 系のそれなので、Ubuntu などをインストールしたことのある人はまったく同じです。やり方は検索すればいくらでも出てくるので書きません。マルチブートにつては過去記事に多少詳しく書きました。
インストール終了後、立ち上げてまずネット接続します。これも Ubuntu と同じです。無線LAN はたぶんパスワードの入力だけで簡単に繫がるでしょう。
まずはシステムのアップデートから。
$ sudo apt update $ sudo apt upgrade
このままでは日本語環境になっていないので、日本語環境に設定します。[Complete Installation] はクリックしておいた方がよいでしょう。
設定したらログアウト→再ログインして下さい。メニューなどが日本語になっている筈です。
日本語入力。mozc をインストールします。
$ sudo apt-get install fcitx-mozc
インストール終了後、再起動で有効化します。
ファイルマネージャは「Nemo」を使いたかったのであるが、OS との相性が悪いらしくバグが出るので諦める。
簡易IDE の「Geany」をインストール。ただしこのままだと組み込みの端末が使えないので、
$ sudo apt-get install libvte9
で OK。
Ruby のインストール。2.5.0 を入れる。
Linux Mint に rbenv で Ruby を入れる - Camera Obscura
さらに Bundler を入れて必要な Gem を入れるまでにはすごく時間がかかるので、諦めて待つ。
- OpenGL 関連
- $ sudo apt-get install libgl1-mesa-dri libglu1-mesa freeglut3 libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
- Gosu 関連
- $ sudo apt-get install build-essential libsdl2-dev libsdl2-ttf-dev libpango1.0-dev libgl1-mesa-dev libopenal-dev libsndfile-dev libmpg123-dev libgmp-dev
- RMagick 関連
- $ sudo apt-get install libmagickwand-dev
elementaryOS は Mac っぽいオシャレさが売りですが、デフォルトのアプリケーションは少ないですね。必要なものは自分で入れていかないといけないようです。
最短ヌクレオチド連鎖問題
require 'bundler/setup' require 'kaki/utils/nest_loop' class Codon include Comparable def initialize(st) @cd = st end attr_reader :cd def <=>(a) x, y = @cd, a.cd l = r = 0 l = if x[1..2] == y[0..1] 2 elsif x[2] == y[0] 1 else 0 end r = if y[1..2] == x[0..1] 2 elsif y[2] == x[0] 1 else 0 end r - l end def inspect @cd end alias :to_s :inspect end def calc(x, y) if x.cd[1..2] == y.cd[0..1] 2 elsif x.cd[2] == y.cd[0] 1 else 0 end end a = [*0..3] codon = [a, a, a].nest_loop {|x| x.join}.map {|x| Codon.new(x)} max = 0 loop do c = codon.shuffle.sort 20.times do co = 0 c.each_cons(2) {|x, y| co += calc(x, y)} if max < co max = co puts 64 * 3 - max p c end c1 = c.sort break if c1 == c c = c1 end end
これまでの最小値。
105 [123, 231, 113, 132, 320, 200, 001, 120, 201, 010, 211, 100, 003, 033, 002, 023, 013, 133, 333, 330, 303, 031, 313, 332, 102, 021, 101, 012, 223, 232, 203, 321, 301, 331, 311, 112, 322, 220, 202, 212, 210, 230, 030, 300, 000, 020, 011, 111, 110, 130, 302, 122, 032, 323, 233, 312, 022, 222, 221, 121, 213, 131, 310, 103]
挿入ソートのベンチマーク(Ruby)
Rubyっぽく書いたのと教科書の擬似コードをそのまま書いたものとの比較。
require 'benchmark' class Array def insertion_sort1 ar = self (size - 1).times do |i| key = ar[i + 1] j = ar.index {|x| x >= key} next if j >= i + 1 ar = ar[0...j] + [key] + ar[j..i] + ar[i + 2..-1] end ar end def insertion_sort2 (size - 1).times do |j| key = at(j + 1) i = j while i >= 0 and at(i) > key self[i + 1] = at(i) i -= 1 end self[i + 1] = key end self end end ar = [*0..10000].shuffle Benchmark.bm do |x| x.report {ar.dup.insertion_sort1} x.report {ar.dup.insertion_sort2} end
1 の方は非破壊的で安定でない、2 の方は破壊的で安定。
結果。
user system total real 1.430000 0.070000 1.500000 ( 1.498388) 2.330000 0.000000 2.330000 ( 2.330626)
Rubyっぽく書いた方が約1.5倍速かった。
もうひとつ思いついた。破壊的で安定でない。
class Array def insertion_sort3 (size - 1).times do |i| key = at(i + 1) j = index{|x| x >= key} if j != i + 1 delete_at(i + 1) insert(j, key) end end self end end
結果。
user system total real 1.370000 0.080000 1.450000 ( 1.451847) 2.390000 0.000000 2.390000 ( 2.386278) 1.250000 0.000000 1.250000 ( 1.250350)
これがいちばん速かった。意外。
アルゴリズムイントロダクション 第3版 第1巻: 基礎・ソート・データ構造・数学 (世界標準MIT教科書)
- 作者: T.コルメン,R.リベスト,C.シュタイン,C.ライザーソン,浅野哲夫,岩野和生,梅尾博司,山下雅史,和田幸一
- 出版社/メーカー: 近代科学社
- 発売日: 2012/08/02
- メディア: 単行本
- 購入: 1人 クリック: 16回
- この商品を含むブログ (20件) を見る
Ruby GTK 覚え書き
これは使えそう。STDIN を必要なファイルディスクリプタにすればよい。
require 'bundler/setup' require 'gtk2' w = Gtk::Window.new w.set_size_request(200, 50) w.set_resizable(false) b = Gtk::VBox.new w.add(b) entry = Gtk::Entry.new entry.set_editable(false) b.pack_start(entry) ioc = GLib::IOChannel.new(STDIN) ioc.add_watch(GLib::IOChannel::IN) do |io| st = io.readline.chomp entry.set_text(st) true #繰り返す end context = GLib::MainContext.default mainloop = GLib::MainLoop.new(context, true) w.signal_connect("destroy") {mainloop.quit} w.show_all mainloop.run ioc.close
参考:
https://github.com/taf2/ruby-gnome2/blob/master/glib/sample/iochannel.rb#L24
C言語/GTKでファイルやらソケットやらのfdが読み込み(or書き込み)可能になるのを待ちたい。 - BlankTar
サンプル(9/17)
サーバー側。こちらが先に起動。
require 'bundler/setup' require 'gtk2' require 'socket' module Sample class MyWindow < Gtk::Window def initialize super("Sample") set_size_request(200, 60) set_resizable(false) entry = Gtk::Entry.new entry.set_editable(false) entry.set_height_request(40) entry.modify_font(Pango::FontDescription.new("13")) add(entry) io = (ARGV[0] == "-s") ? TCPServer.open(29753) : STDIN Thread.new(io) do |io| ioc = GLib::IOChannel.new((io.class == IO) ? io : io.accept) ioc.add_watch(GLib::IOChannel::IN) do |i| st = i.gets next unless st entry.set_text(st.chomp) true #繰り返し end end signal_connect("destroy") {Gtk.main_quit} show_all end end def self.run MyWindow.new Gtk.main end end Sample.run
クライアント側。
require 'socket' TCPSocket.open("localhost", 29753) do |sock| st = "Hello, World!" st.length.times do |i| sock.puts st[0, i + 1] sleep(1) end end
単純にこんなのでも。
require 'socket' TCPSocket.open("localhost", 29753) do |sock| loop {sock.puts(gets)} end
Enumerator への追加は deep copy されるのか(Ruby)
どうもそうなのではないかと思って確かめてみたら、やはりそうだった。これは助かる。
$ pry [1] pry(main)> e = Enumerator.new do |y| [1] pry(main)* a = ["aiueo", "Ruby"] [1] pry(main)* y << a [1] pry(main)* a[0] = "oeuia" [1] pry(main)* y << a [1] pry(main)* a[0][1] = "nya" [1] pry(main)* y << a [1] pry(main)* end => #<Enumerator: ...> [2] pry(main)> loop {p e.next} ["aiueo", "Ruby"] ["oeuia", "Ruby"] ["onyauia", "Ruby"] => #<Enumerator::Yielder:0x0056471aa90738>
つまりオブジェクトの完全なスナップショットを取れるということ。
いや、ちがうな。
[3] pry(main)> e.rewind => #<Enumerator: ...> [4] pry(main)> loop {p e.next.object_id} 47431695117340 47431695117340 47431695117340 => #<Enumerator::Yielder:0x0056471aad58b0>
object_id はすべて同じだ。そうか、Enumerator は Fiber を使って実装されているのだから、y << a した時点で止まってしまうのだな。で、e.next されるたびに更新されると。だから deep copy ではない。実際、to_a してみればわかる。
[5] pry(main)> e.rewind => #<Enumerator: ...> [6] pry(main)> e.to_a => [["onyauia", "Ruby"], ["onyauia", "Ruby"], ["onyauia", "Ruby"]]