├── zh_CN ├── q17_02.rb ├── q11_01.js ├── q45_03.rb ├── q43_02.rb ├── q59_02.rb ├── q03_02.rb ├── q05_02.rb ├── q11_03.rb ├── q22_01.rb ├── q16_02.rb ├── q45_02.rb ├── q11_02.js ├── q04_02.rb ├── q01_01.rb ├── q56_01.rb ├── q07_01.rb ├── q11_04.rb ├── q21_02.rb ├── q03_01.rb ├── q40_01.rb ├── q04_01.rb ├── q17_01.rb ├── q35_02.rb ├── q46_02.rb ├── q23_01.rb ├── q05_03.rb ├── q06_01.rb ├── q16_01.rb ├── q42_01.rb ├── q15_01.rb ├── q56_03.rb ├── q09_01.rb ├── q20_01.rb ├── q35_01.rb ├── q28_01.rb ├── q08_01.rb ├── q20_02.rb ├── q41_02.rb ├── q56_02.rb ├── q12_01.rb ├── q40_02.rb ├── q21_01.rb ├── q36_02.rb ├── q01_02.js ├── q02_02.php ├── q15_03.rb ├── q53_03.rb ├── q05_01.rb ├── q13_01.rb ├── q07_02.rb ├── q15_02.rb ├── q39_01.rb ├── q37_01.rb ├── q19_01.rb ├── q28_02.rb ├── q28_03.rb ├── q53_02.rb ├── q56_04.js ├── q24_01.rb ├── q50_02.rb ├── q02_01.js ├── q13_02.rb ├── q39_03.rb ├── q36_01.rb ├── q31_02.js ├── q46_01.rb ├── q42_02.rb ├── q48_01.rb ├── q45_01.rb ├── q53_01.rb ├── q34_01.rb ├── q37_02.rb ├── q61_01.rb ├── q09_02.js ├── q67_01.rb ├── q47_01.rb ├── q55_01.rb ├── q67_02.rb ├── q18_01.rb ├── q52_01.rb ├── q62-extra-workday.txt ├── q39_02.rb ├── q51_01.rb ├── q25_01.rb ├── q55_02.rb ├── q69_01.rb ├── q36_03.rb ├── q10_02.rb ├── q69_03.rb ├── q61_03.c ├── q44_01.rb ├── q38_01.rb ├── q55_03.js ├── q65_01.rb ├── q18_02.rb ├── q13_03.rb ├── q31_01.js ├── q10_01.rb ├── q54_02.rb ├── q68_01.rb ├── q60_01.rb ├── q37_03.rb ├── q64_01.rb ├── q44_02.rb ├── q26_02.rb ├── q30_01.rb ├── q48_02.js ├── q57_01.rb ├── q30_02.rb ├── q33_01.rb ├── q14_02.rb ├── q49_01.rb ├── q36_04.js ├── q30_03.js ├── q27_01.rb ├── q69_02.c ├── q14_01.rb ├── q49_02.js ├── q62_02.rb ├── q61_02.rb ├── q64_02.rb ├── q29_01.rb ├── q65_02.rb ├── q37_04.js ├── q59_04.rb ├── q59_01.rb ├── q63_01.rb ├── q59_03.rb ├── q26_01.rb ├── q62_01.rb ├── q63_02.rb ├── q60_02.rb └── q58_02.rb ├── ja_JP ├── q17_02.rb ├── q11_01.js ├── q46_03.rb ├── q44_02.rb ├── q60_02.rb ├── q03_02.rb ├── q05_02.rb ├── q11_03.rb ├── q22_01.rb ├── q16_02.rb ├── q46_02.rb ├── q11_02.js ├── q04_02.rb ├── q01_01.rb ├── q07_01.rb ├── q57_01.rb ├── q11_04.rb ├── q21_02.rb ├── q03_01.rb ├── q04_01.rb ├── q41_01.rb ├── q36_02.rb ├── q05_03.rb ├── q23_01.rb ├── q47_02.rb ├── q17_01.rb ├── q42_01.rb ├── q16_01.rb ├── q06_01.rb ├── q43_01.rb ├── q09_01.rb ├── q57_03.rb ├── q15_01.rb ├── q36_01.rb ├── q20_01.rb ├── q08_01.rb ├── q28_01.rb ├── q20_02.rb ├── q42_02.rb ├── q12_01.rb ├── q57_02.rb ├── q41_02.rb ├── q02_02.php ├── q21_01.rb ├── q37_02.rb ├── q54_03.rb ├── q01_02.js ├── q15_03.rb ├── q05_01.rb ├── q33_01.rb ├── q51_01.rb ├── q13_01.rb ├── q07_02.rb ├── q40_01.rb ├── q15_02.rb ├── q19_01.rb ├── q28_02.rb ├── q38_01.rb ├── q28_03.rb ├── q54_02.rb ├── q51_02.rb ├── q57_04.js ├── q02_01.js ├── q13_02.rb ├── q24_01.rb ├── q40_03.rb ├── q37_01.rb ├── q31_02.js ├── q47_01.rb ├── q43_02.rb ├── q46_01.rb ├── q49_01.rb ├── q54_01.rb ├── q35_01.rb ├── q09_02.js ├── q38_02.rb ├── q62_01.rb ├── q68_01.rb ├── q48_01.rb ├── q56_01.rb ├── q68_02.rb ├── q18_01.rb ├── q53_01.rb ├── q52_01.rb ├── q40_02.rb ├── q25_01.rb ├── q10_02.rb ├── q55_01.rb ├── q56_02.rb ├── q70_01.rb ├── q37_03.rb ├── q62_03.c ├── q70_03.rb ├── q45_01.rb ├── q44_01.rb ├── q39_01.rb ├── q56_03.js ├── q66_01.rb ├── q18_02.rb ├── q13_03.rb ├── q31_01.js ├── q59_01.rb ├── q10_01.rb ├── q61_01.rb ├── q69_01.rb ├── q55_02.rb ├── q38_03.rb ├── q45_02.rb ├── q65_01.rb ├── q26_02.rb ├── q30_01.rb ├── q49_02.js ├── q30_02.rb ├── q34_01.rb ├── q58_01.rb ├── q14_02.rb ├── q50_01.rb ├── q63_02.rb ├── q37_04.js ├── q30_03.js ├── q27_01.rb ├── q70_02.c ├── q14_01.rb ├── q50_02.js ├── q67_01.rb ├── q65_02.rb ├── q63_01.rb ├── q66_02.rb ├── q29_01.rb ├── q62_02.rb ├── q64_01.rb ├── q38_04.js ├── q60_04.rb ├── q60_01.rb ├── q60_03.rb ├── q64_02.rb ├── q26_01.rb ├── q59_02.rb └── q61_02.rb ├── rename.js ├── README.md ├── .gitignore └── LICENSE /zh_CN/q17_02.rb: -------------------------------------------------------------------------------- 1 | N = 30 2 | boy, girl = 1, 0 3 | N.times{|i| 4 | # 求已排列n-1人时的状态 5 | boy, girl = boy + girl, boy 6 | } 7 | puts boy + girl 8 | -------------------------------------------------------------------------------- /ja_JP/q17_02.rb: -------------------------------------------------------------------------------- 1 | N = 30 2 | boy, girl = 1, 0 3 | N.times{|i| 4 | # n-1人まで並んでいる状態から求める 5 | boy, girl = boy + girl, boy 6 | } 7 | puts boy + girl 8 | -------------------------------------------------------------------------------- /ja_JP/q11_01.js: -------------------------------------------------------------------------------- 1 | function fib(n){ 2 | if ((n == 0) || (n == 1)){ 3 | return 1; 4 | } else { 5 | return fib(n - 2) + fib(n - 1); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ja_JP/q46_03.rb: -------------------------------------------------------------------------------- 1 | def count_swap(n) 2 | return 0 if n == 1 3 | (n - 1) * (1..(n-1)).inject(1, :*) + n * count_swap(n - 1) 4 | end 5 | puts count_swap(7) 6 | -------------------------------------------------------------------------------- /zh_CN/q11_01.js: -------------------------------------------------------------------------------- 1 | function fib(n){ 2 | if ((n == 0) || (n == 1)){ 3 | return 1; 4 | } else { 5 | return fib(n - 2) + fib(n - 1); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /zh_CN/q45_03.rb: -------------------------------------------------------------------------------- 1 | def count_swap(n) 2 | return 0 if n == 1 3 | (n - 1) * (1..(n-1)).inject(1, :*) + n * count_swap(n - 1) 4 | end 5 | puts count_swap(7) 6 | -------------------------------------------------------------------------------- /ja_JP/q44_02.rb: -------------------------------------------------------------------------------- 1 | cnt = 0 2 | 10.step(100, 2){|a| 3 | (1..(a / 2 - 1)).each{|c| 4 | b = a - c 5 | cnt += 1 if b.gcd(c) == 1 6 | } 7 | } 8 | puts cnt 9 | -------------------------------------------------------------------------------- /zh_CN/q43_02.rb: -------------------------------------------------------------------------------- 1 | cnt = 0 2 | 10.step(100, 2){|a| 3 | (1..(a / 2 - 1)).each{|c| 4 | b = a - c 5 | cnt += 1 if b.gcd(c) == 1 6 | } 7 | } 8 | puts cnt 9 | -------------------------------------------------------------------------------- /ja_JP/q60_02.rb: -------------------------------------------------------------------------------- 1 | a = [1, 2, 3, 4] 2 | b = a.clone 3 | b[0] = 5 4 | p a 5 | p b 6 | 7 | c = [[1, 2], [3, 4]] 8 | d = c.clone 9 | d[0][0] = 5 10 | p c 11 | p d 12 | -------------------------------------------------------------------------------- /zh_CN/q59_02.rb: -------------------------------------------------------------------------------- 1 | a = [1, 2, 3, 4] 2 | b = a.clone 3 | b[0] = 5 4 | p a 5 | p b 6 | 7 | c = [[1, 2], [3, 4]] 8 | d = c.clone 9 | d[0][0] = 5 10 | p c 11 | p d 12 | -------------------------------------------------------------------------------- /ja_JP/q03_02.rb: -------------------------------------------------------------------------------- 1 | (1..100).each{|i| 2 | flag = false 3 | (1..100).each{|j| 4 | if i % j == 0 then 5 | flag = !flag 6 | end 7 | } 8 | puts i if flag 9 | } 10 | -------------------------------------------------------------------------------- /zh_CN/q03_02.rb: -------------------------------------------------------------------------------- 1 | (1..100).each{|i| 2 | flag = false 3 | (1..100).each{|j| 4 | if i % j == 0 then 5 | flag = !flag 6 | end 7 | } 8 | puts i if flag 9 | } 10 | -------------------------------------------------------------------------------- /ja_JP/q05_02.rb: -------------------------------------------------------------------------------- 1 | coins = [10, 50, 100, 500] 2 | cnt = 0 3 | (2..15).each do |i| 4 | coins.repeated_combination(i).each{|coin_set| 5 | cnt += 1 if coin_set.inject(:+) == 1000 6 | } 7 | end 8 | puts cnt 9 | -------------------------------------------------------------------------------- /zh_CN/q05_02.rb: -------------------------------------------------------------------------------- 1 | coins = [10, 50, 100, 500] 2 | cnt = 0 3 | (2..15).each do |i| 4 | coins.repeated_combination(i).each{|coin_set| 5 | cnt += 1 if coin_set.inject(:+) == 1000 6 | } 7 | end 8 | puts cnt 9 | -------------------------------------------------------------------------------- /ja_JP/q11_03.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def fib(n) 3 | return @memo[n] if @memo.has_key?(n) 4 | if (n == 0) || (n == 1) then 5 | @memo[n] = 1 6 | else 7 | @memo[n] = fib(n - 1) + fib(n - 2) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /zh_CN/q11_03.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def fib(n) 3 | return @memo[n] if @memo.has_key?(n) 4 | if (n == 0) || (n == 1) then 5 | @memo[n] = 1 6 | else 7 | @memo[n] = fib(n - 1) + fib(n - 2) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ja_JP/q22_01.rb: -------------------------------------------------------------------------------- 1 | n = 16 2 | pair = Array.new(n / 2 + 1) 3 | pair[0] = 1 4 | 5 | 1.upto(n/2){|i| 6 | pair[i] = 0 7 | i.times{|j| 8 | pair[i] += pair[j] * pair[i - j - 1] 9 | } 10 | } 11 | 12 | puts pair[n/2] 13 | -------------------------------------------------------------------------------- /zh_CN/q22_01.rb: -------------------------------------------------------------------------------- 1 | n = 16 2 | pair = Array.new(n / 2 + 1) 3 | pair[0] = 1 4 | 5 | 1.upto(n/2){|i| 6 | pair[i] = 0 7 | i.times{|j| 8 | pair[i] += pair[j] * pair[i - j - 1] 9 | } 10 | } 11 | 12 | puts pair[n/2] 13 | -------------------------------------------------------------------------------- /ja_JP/q16_02.rb: -------------------------------------------------------------------------------- 1 | MAX = 500 2 | 3 | cnt = 0 4 | (1..MAX/4).each{|c| # 正方形の一辺 5 | (1..(c-1)).to_a.combination(2){|a, b| 6 | if a * a + b * b == c * c then 7 | cnt += 1 if a.gcd(b) == 1 8 | end 9 | } 10 | } 11 | puts cnt 12 | -------------------------------------------------------------------------------- /zh_CN/q16_02.rb: -------------------------------------------------------------------------------- 1 | MAX = 500 2 | 3 | cnt = 0 4 | (1..MAX/4).each{|c| # 正方形边长 5 | (1..(c-1)).to_a.combination(2){|a, b| 6 | if a * a + b * b == c * c then 7 | cnt += 1 if a.gcd(b) == 1 8 | end 9 | } 10 | } 11 | puts cnt 12 | -------------------------------------------------------------------------------- /ja_JP/q46_02.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (1..7).to_a.permutation.each{|ary| 3 | ary.size.times{|i| 4 | j = ary.index(i + 1) 5 | if i != j then 6 | ary[i], ary[j] = ary[j], ary[i] 7 | count += 1 8 | end 9 | } 10 | } 11 | puts count 12 | -------------------------------------------------------------------------------- /zh_CN/q45_02.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (1..7).to_a.permutation.each{|ary| 3 | ary.size.times{|i| 4 | j = ary.index(i + 1) 5 | if i != j then 6 | ary[i], ary[j] = ary[j], ary[i] 7 | count += 1 8 | end 9 | } 10 | } 11 | puts count 12 | -------------------------------------------------------------------------------- /ja_JP/q11_02.js: -------------------------------------------------------------------------------- 1 | var memo = new Array() 2 | function fib(n){ 3 | if (memo[n] == null){ 4 | if ((n == 0) || (n == 1)){ 5 | memo[n] = 1; 6 | } else { 7 | memo[n] = fib(n - 2) + fib(n - 1); 8 | } 9 | } 10 | return memo[n]; 11 | } 12 | -------------------------------------------------------------------------------- /zh_CN/q11_02.js: -------------------------------------------------------------------------------- 1 | var memo = new Array() 2 | function fib(n){ 3 | if (memo[n] == null){ 4 | if ((n == 0) || (n == 1)){ 5 | memo[n] = 1; 6 | } else { 7 | memo[n] = fib(n - 2) + fib(n - 1); 8 | } 9 | } 10 | return memo[n]; 11 | } 12 | -------------------------------------------------------------------------------- /ja_JP/q04_02.rb: -------------------------------------------------------------------------------- 1 | def cutbar(m, n) 2 | count = 0 3 | current = 1 # currentは現在の長さ 4 | while n > current do 5 | current += current < m ? current : m 6 | count = count + 1 7 | end 8 | puts(count) 9 | end 10 | 11 | cutbar(3, 20) 12 | cutbar(5, 100) 13 | -------------------------------------------------------------------------------- /zh_CN/q04_02.rb: -------------------------------------------------------------------------------- 1 | def cutbar(m, n) 2 | count = 0 3 | current = 1 # current是当前长度 4 | while n > current do 5 | current += current < m ? current : m 6 | count = count + 1 7 | end 8 | puts(count) 9 | end 10 | 11 | cutbar(3, 20) 12 | cutbar(5, 100) 13 | -------------------------------------------------------------------------------- /zh_CN/q01_01.rb: -------------------------------------------------------------------------------- 1 | # 从11开始检索 2 | num = 11 3 | while true 4 | if num.to_s == num.to_s.reverse && 5 | num.to_s(8) == num.to_s(8).reverse && 6 | num.to_s(2) == num.to_s(2).reverse 7 | puts num 8 | break 9 | end 10 | # 只检索奇数,每次加2 11 | num += 2 12 | end 13 | -------------------------------------------------------------------------------- /ja_JP/q01_01.rb: -------------------------------------------------------------------------------- 1 | # 11から探索開始 2 | num = 11 3 | while true 4 | if num.to_s == num.to_s.reverse && 5 | num.to_s(8) == num.to_s(8).reverse && 6 | num.to_s(2) == num.to_s(2).reverse 7 | puts num 8 | break 9 | end 10 | # 奇数だけを探すため、2つずつ増やす 11 | num += 2 12 | end 13 | -------------------------------------------------------------------------------- /zh_CN/q56_01.rb: -------------------------------------------------------------------------------- 1 | # 竖线和横线 2 | v, h = 7, 10 3 | total = 0 4 | # 对“下方的数字”,统计需要交换位置的数字 5 | (0..(v-1)).to_a.permutation.each{|final| 6 | cnt = 0 7 | v.times{|i| 8 | cnt += final.take_while{|j| j != i}.count{|k| k > i} 9 | } 10 | total += 1 if cnt == h 11 | } 12 | puts total 13 | -------------------------------------------------------------------------------- /zh_CN/q07_01.rb: -------------------------------------------------------------------------------- 1 | # 读入处理日期的Date库 2 | require 'date' 3 | 4 | # 指定遍历的日期区间 5 | term = Date.parse('19641010')..Date.parse('20200724') 6 | 7 | # 转换成数值 8 | term_list = term.map{|d|d.strftime('%Y%m%d').to_i} 9 | 10 | # 输出转换结果和自身一致的值 11 | puts term_list.select{|d|d==d.to_s(2).reverse.to_i(2)} 12 | -------------------------------------------------------------------------------- /zh_CN/q11_04.rb: -------------------------------------------------------------------------------- 1 | a = b = 1 2 | count = 0 3 | while (count < 11) do 4 | c = a + b 5 | # 分开各个数位进行求和 6 | sum = 0 7 | c.to_s.split(//).each {|e| sum += e.to_i} 8 | if (c % sum == 0) then 9 | # 输出能整除的情况 10 | puts c 11 | count += 1 12 | end 13 | a, b = b, c 14 | end 15 | -------------------------------------------------------------------------------- /ja_JP/q07_01.rb: -------------------------------------------------------------------------------- 1 | # 日付を扱うDateクラスを読込 2 | require 'date' 3 | 4 | # 抽出対象の期間を設定 5 | term = Date.parse('19641010')..Date.parse('20200724') 6 | 7 | # 数値化 8 | term_list = term.map{|d|d.strftime('%Y%m%d').to_i} 9 | 10 | # 処理した結果が同じ値になるものを出力 11 | puts term_list.select{|d|d==d.to_s(2).reverse.to_i(2)} 12 | -------------------------------------------------------------------------------- /ja_JP/q57_01.rb: -------------------------------------------------------------------------------- 1 | # 縦線と横線 2 | v, h = 7, 10 3 | total = 0 4 | # 「下の数」の位置について、交換する必要のある数をカウント 5 | (0..(v-1)).to_a.permutation.each{|final| 6 | cnt = 0 7 | v.times{|i| 8 | cnt += final.take_while{|j| j != i}.count{|k| k > i} 9 | } 10 | total += 1 if cnt == h 11 | } 12 | puts total 13 | -------------------------------------------------------------------------------- /ja_JP/q11_04.rb: -------------------------------------------------------------------------------- 1 | a = b = 1 2 | count = 0 3 | while (count < 11) do 4 | c = a + b 5 | # 1桁ずつに分割して各桁の和を取得 6 | sum = 0 7 | c.to_s.split(//).each {|e| sum += e.to_i} 8 | if (c % sum == 0) then 9 | # 割り切れた場合に出力する 10 | puts c 11 | count += 1 12 | end 13 | a, b = b, c 14 | end 15 | -------------------------------------------------------------------------------- /zh_CN/q21_02.rb: -------------------------------------------------------------------------------- 1 | count = 0 # “0”出现的次数 2 | line = 1 # 当前行的行数 3 | row = 1 # 当前行的值(二进制码) 4 | 5 | while count < 2014 do 6 | row ^= row << 1 # 从前一行做异或运算得到下一行 7 | count += row.to_s(2).count("0") # 统计“0”出现的次数 8 | line += 1 9 | end 10 | 11 | puts line # 统计到2014个“0”时的行 12 | -------------------------------------------------------------------------------- /ja_JP/q21_02.rb: -------------------------------------------------------------------------------- 1 | count = 0 # 「0」が出現した回数 2 | line = 1 # 現在の行数 3 | row = 1 # 現在の行の値(ビット列) 4 | 5 | while count < 2014 do 6 | row ^= row << 1 # 前行から排他的論理和で次の行をセット 7 | count += row.to_s(2).count("0") # 「0」の数をカウント 8 | line += 1 9 | end 10 | 11 | puts line # 2014個カウントした行を出力 12 | -------------------------------------------------------------------------------- /zh_CN/q03_01.rb: -------------------------------------------------------------------------------- 1 | # 初始化卡牌 2 | N = 100 3 | cards = Array.new(N, false) 4 | 5 | # 从2到N翻牌 6 | (2..N).each{|i| 7 | j = i - 1 8 | while (j < cards.size) do 9 | cards[j] = !cards[j] 10 | j += i 11 | end 12 | } 13 | 14 | # 输出背面朝上的牌 15 | N.times{|i| 16 | puts i + 1 if !cards[i] 17 | } 18 | -------------------------------------------------------------------------------- /ja_JP/q03_01.rb: -------------------------------------------------------------------------------- 1 | # カードの初期化 2 | N = 100 3 | cards = Array.new(N, false) 4 | 5 | # 2〜Nまで裏返す 6 | (2..N).each{|i| 7 | j = i - 1 8 | while (j < cards.size) do 9 | cards[j] = !cards[j] 10 | j += i 11 | end 12 | } 13 | 14 | # 裏向きのカードを出力 15 | N.times{|i| 16 | puts i + 1 if !cards[i] 17 | } 18 | -------------------------------------------------------------------------------- /zh_CN/q40_01.rb: -------------------------------------------------------------------------------- 1 | ip = Array.new 2 | (1 << 16).times{|i| 3 | # 反转16位的数字 4 | j = ('%016b' % i).reverse.to_i(2) 5 | 6 | # 生成分割的十进制数字符串 7 | s = '%d.%d.%d.%d' % [i>>8, i&0xff, j>>8, j&0xff] 8 | 9 | # 如果只用到了10个数字和点号,则符合条件 10 | ip.push(s) if s.split("").uniq.length == 11 11 | } 12 | puts ip.size 13 | puts ip 14 | -------------------------------------------------------------------------------- /zh_CN/q04_01.rb: -------------------------------------------------------------------------------- 1 | def cutbar(m, n, current) # current是目前木棒的数目 2 | if current >= n then 3 | 0 # 完成切分 4 | elsif current < m then 5 | 1 + cutbar(m, n, current * 2) # 接下来是现在数目的2倍 6 | else 7 | 1 + cutbar(m, n, current + m) # 加上刀的数目 8 | end 9 | end 10 | 11 | puts cutbar(3, 20, 1) 12 | puts cutbar(5, 100, 1) 13 | -------------------------------------------------------------------------------- /ja_JP/q04_01.rb: -------------------------------------------------------------------------------- 1 | def cutbar(m, n, current) # currentは現在の棒の数 2 | if current >= n then 3 | 0 # 切り終えた 4 | elsif current < m then 5 | 1 + cutbar(m, n, current * 2) # 次は現在の2倍になる 6 | else 7 | 1 + cutbar(m, n, current + m) # はさみの数だけ追加 8 | end 9 | end 10 | 11 | puts cutbar(3, 20, 1) 12 | puts cutbar(5, 100, 1) 13 | -------------------------------------------------------------------------------- /ja_JP/q41_01.rb: -------------------------------------------------------------------------------- 1 | ip = Array.new 2 | (1 << 16).times{|i| 3 | # 16ビットの数を反転する 4 | j = ('%016b' % i).reverse.to_i(2) 5 | 6 | # 10進数のドット区切りの文字列を生成 7 | s = '%d.%d.%d.%d' % [i>>8, i&0xff, j>>8, j&0xff] 8 | 9 | # 10個の数字とドットだけの場合、配列に追加 10 | ip.push(s) if s.split("").uniq.length == 11 11 | } 12 | puts ip.size 13 | puts ip 14 | -------------------------------------------------------------------------------- /ja_JP/q36_02.rb: -------------------------------------------------------------------------------- 1 | n = (1..50).select{|i| (i % 2 > 0) || (i % 5 > 0)} 2 | answer = Array.new 3 | k = 1 4 | while (n.size > 0) do 5 | x = k.to_s(2).to_i * 7 6 | n.each{|i| 7 | if x % i == 0 then 8 | answer << i if x.to_s == x.to_s.reverse 9 | n.delete(i) 10 | end 11 | } 12 | k += 1 13 | end 14 | puts answer.sort 15 | -------------------------------------------------------------------------------- /zh_CN/q17_01.rb: -------------------------------------------------------------------------------- 1 | # 用字符表示男女 2 | @boy, @girl = "B", "G" 3 | N = 30 4 | 5 | def add(seq) 6 | # 到达排列人数上限,终止递归 7 | return 1 if seq.size == N 8 | 9 | # 未满30人时,加男生,当右边为男生时加女生 10 | cnt = add(seq + @boy) 11 | cnt += add(seq + @girl) if seq[-1] == @boy 12 | return cnt 13 | end 14 | 15 | # 从男生或者女生开始 16 | puts add(@boy) + add(@girl) 17 | -------------------------------------------------------------------------------- /zh_CN/q35_02.rb: -------------------------------------------------------------------------------- 1 | n = (1..50).select{|i| (i % 2 > 0) || (i % 5 > 0)} 2 | answer = Array.new 3 | k = 1 4 | while (n.size > 0) do 5 | x = k.to_s(2).to_i * 7 6 | n.each{|i| 7 | if x % i == 0 then 8 | answer << i if x.to_s == x.to_s.reverse 9 | n.delete(i) 10 | end 11 | } 12 | k += 1 13 | end 14 | puts answer.sort 15 | -------------------------------------------------------------------------------- /zh_CN/q46_02.rb: -------------------------------------------------------------------------------- 1 | N = 4 2 | 3 | def search(rows) 4 | return 1 if rows.size == N # 已搜索完所有行,结束搜索 5 | count = 0 6 | (2**N).times{|row| 7 | # 四个对角○和×是否交错出现 8 | cross = rows.select{|r| (row & ~r) > 0 && (~row & r) > 0} 9 | count += search(rows + [row]) if cross.count == 0 10 | } 11 | count 12 | end 13 | 14 | puts search([]) 15 | -------------------------------------------------------------------------------- /zh_CN/q23_01.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | 3 | def game(coin, depth) 4 | return @memo[[coin, depth]] if @memo.has_key?([coin, depth]) 5 | return 0 if coin == 0 6 | return 1 if depth == 0 7 | win = game(coin + 1, depth - 1) # 获胜时 8 | lose = game(coin - 1, depth - 1) # 落败时 9 | @memo[[coin, depth]] = win + lose 10 | end 11 | 12 | puts game(10, 24) 13 | -------------------------------------------------------------------------------- /ja_JP/q05_03.rb: -------------------------------------------------------------------------------- 1 | @cnt = 0 2 | def change(target, coins, usable) 3 | coin = coins.shift 4 | if coins.size == 0 then 5 | @cnt += 1 if target / coin <= usable 6 | else 7 | (0..target/coin).each{|i| 8 | change(target - coin * i, coins.clone, usable - i) 9 | } 10 | end 11 | end 12 | change(1000, [500, 100, 50, 10], 15) 13 | puts @cnt 14 | -------------------------------------------------------------------------------- /ja_JP/q23_01.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | 3 | def game(coin, depth) 4 | return @memo[[coin, depth]] if @memo.has_key?([coin, depth]) 5 | return 0 if coin == 0 6 | return 1 if depth == 0 7 | win = game(coin + 1, depth - 1) # 勝ったとき 8 | lose = game(coin - 1, depth - 1) # 負けたとき 9 | @memo[[coin, depth]] = win + lose 10 | end 11 | 12 | puts game(10, 24) 13 | -------------------------------------------------------------------------------- /ja_JP/q47_02.rb: -------------------------------------------------------------------------------- 1 | N = 4 2 | 3 | def search(rows) 4 | return 1 if rows.size == N # すべての行を探索したら終了 5 | count = 0 6 | (2**N).times{|row| 7 | # 4隅に○と×が交互になっているかチェック 8 | cross = rows.select{|r| (row & ~r) > 0 && (~row & r) > 0} 9 | count += search(rows + [row]) if cross.count == 0 10 | } 11 | count 12 | end 13 | 14 | puts search([]) 15 | -------------------------------------------------------------------------------- /zh_CN/q05_03.rb: -------------------------------------------------------------------------------- 1 | @cnt = 0 2 | def change(target, coins, usable) 3 | coin = coins.shift 4 | if coins.size == 0 then 5 | @cnt += 1 if target / coin <= usable 6 | else 7 | (0..target/coin).each{|i| 8 | change(target - coin * i, coins.clone, usable - i) 9 | } 10 | end 11 | end 12 | change(1000, [500, 100, 50, 10], 15) 13 | puts @cnt 14 | -------------------------------------------------------------------------------- /zh_CN/q06_01.rb: -------------------------------------------------------------------------------- 1 | # 检测是否形成环 2 | def is_loop(n) 3 | # 最开始乘以3加1 4 | check = n * 3 + 1 5 | # 一直循环到数字变为1 6 | while check != 1 do 7 | check = check.even? ? check / 2 : check * 3 + 1 8 | return true if check == n 9 | end 10 | return false 11 | end 12 | 13 | # 检查2~10000之间的所有偶数 14 | puts 2.step(10000, 2).count{|i| 15 | is_loop(i) 16 | } 17 | -------------------------------------------------------------------------------- /ja_JP/q17_01.rb: -------------------------------------------------------------------------------- 1 | # 男子と女子を文字で設定 2 | @boy, @girl = "B", "G" 3 | N = 30 4 | 5 | def add(seq) 6 | # 並べる人数に達したら終了 7 | return 1 if seq.size == N 8 | 9 | # 30人未満の場合、男子を追加するか、右端が男子の場合女子を追加 10 | cnt = add(seq + @boy) 11 | cnt += add(seq + @girl) if seq[-1] == @boy 12 | return cnt 13 | end 14 | 15 | # 男子と女子から開始してカウント 16 | puts add(@boy) + add(@girl) 17 | -------------------------------------------------------------------------------- /ja_JP/q42_01.rb: -------------------------------------------------------------------------------- 1 | op = ['+', '-', '*', '/', ''] 2 | found = false 3 | len = 1 4 | while !found do 5 | op.repeated_permutation(len){|o| 6 | (1..9).to_a.each{|i| 7 | expr = o.inject(i.to_s){|l, n| l + n + i.to_s} 8 | if eval(expr) == 1234 then 9 | puts expr 10 | found = true 11 | end 12 | } 13 | } 14 | len += 1 15 | end 16 | -------------------------------------------------------------------------------- /ja_JP/q16_01.rb: -------------------------------------------------------------------------------- 1 | MAX = 500 2 | 3 | answer = [] 4 | (1..MAX/4).each{|c| # 正方形の一辺 5 | edge = (1..(c-1)).to_a.map{|tate| tate * (2 * c - tate)} 6 | edge.combination(2){|a, b| # 長方形の面積 7 | if a + b == c * c then 8 | answer.push([1, b / a.to_f, c * c / a.to_f]) 9 | end 10 | } 11 | } 12 | answer.uniq! # 整数倍を除外 13 | puts answer.size 14 | -------------------------------------------------------------------------------- /zh_CN/q16_01.rb: -------------------------------------------------------------------------------- 1 | MAX = 500 2 | 3 | answer = [] 4 | (1..MAX/4).each{|c| # 正方形边长 5 | edge = (1..(c-1)).to_a.map{|tate| tate * (2 * c - tate)} 6 | edge.combination(2){|a, b| # 长方形面积 7 | if a + b == c * c then 8 | answer.push([1, b / a.to_f, c * c / a.to_f]) 9 | end 10 | } 11 | } 12 | answer.uniq! # 去除整数倍的情况 13 | puts answer.size 14 | -------------------------------------------------------------------------------- /zh_CN/q42_01.rb: -------------------------------------------------------------------------------- 1 | n = 5 2 | 3 | # 设置初始值 4 | cards = [(1..n*2).to_a] 5 | answer = (1..n*2).to_a.reverse 6 | 7 | depth = 1 8 | while true do 9 | # 搜索 10 | cards = cards.each_with_object([]) do |c, result| 11 | 1.upto(n){|i| result << c[i, n] + c[0, i] + c[i + n..-1]} 12 | end 13 | break if cards.include?(answer) 14 | depth += 1 15 | end 16 | 17 | puts depth 18 | -------------------------------------------------------------------------------- /ja_JP/q06_01.rb: -------------------------------------------------------------------------------- 1 | # ループしているかチェック 2 | def is_loop(n) 3 | # 最初は3をかけて1を足す 4 | check = n * 3 + 1 5 | # 1になるまで数字を変化させることを繰り返す 6 | while check != 1 do 7 | check = check.even? ? check / 2 : check * 3 + 1 8 | return true if check == n 9 | end 10 | return false 11 | end 12 | 13 | # 2〜10000まで、偶数についてチェックする 14 | puts 2.step(10000, 2).count{|i| 15 | is_loop(i) 16 | } 17 | -------------------------------------------------------------------------------- /ja_JP/q43_01.rb: -------------------------------------------------------------------------------- 1 | n = 5 2 | 3 | # 初期値をセット 4 | cards = [(1..n*2).to_a] 5 | answer = (1..n*2).to_a.reverse 6 | 7 | depth = 1 8 | while true do 9 | # 探索 10 | cards = cards.each_with_object([]) do |c, result| 11 | 1.upto(n){|i| result << c[i, n] + c[0, i] + c[i + n..-1]} 12 | end 13 | break if cards.include?(answer) 14 | depth += 1 15 | end 16 | 17 | puts depth 18 | -------------------------------------------------------------------------------- /zh_CN/q15_01.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 楼梯级数 2 | STEPS = 4 # 一次最大前进级数 3 | 4 | def move(a, b) 5 | return 0 if a > b # 如果A级数比B大,则结束搜索 6 | return 1 if a == b # 如果停在同一级,则算入结果 7 | cnt = 0 8 | (1..STEPS).each{|da| 9 | (1..STEPS).each{|db| 10 | cnt += move(a + da, b - db) # 递归搜索 11 | } 12 | } 13 | cnt 14 | end 15 | 16 | # A从0位置开始,B从N位置开始 17 | puts move(0, N) 18 | -------------------------------------------------------------------------------- /zh_CN/q56_03.rb: -------------------------------------------------------------------------------- 1 | # 竖线和横线 2 | @v, @h = 7, 10 3 | 4 | # 递归生成横线 5 | def make_bars(v, h) 6 | new_h = Array.new(h.size + v - 1, 0) 7 | # 统计各横线的情况 8 | v.times{|i| 9 | h.each_with_index{|cnt, j| 10 | new_h[i+j] += cnt 11 | } 12 | } 13 | if v == @v + 1 then 14 | puts h[@h] 15 | else 16 | make_bars(v + 1, new_h) 17 | end 18 | end 19 | make_bars(1, [1]) 20 | -------------------------------------------------------------------------------- /ja_JP/q09_01.rb: -------------------------------------------------------------------------------- 1 | boy, girl = 20, 10 2 | boy, girl = boy + 1, girl + 1 3 | ary = Array.new(boy * girl){0} 4 | ary[0] = 1 5 | girl.times{|g| 6 | boy.times{|b| 7 | if (b != g) && (boy - b != girl - g) then 8 | ary[b + boy * g] += ary[b - 1 + boy * g] if b > 0 9 | ary[b + boy * g] += ary[b + boy * (g - 1)] if g > 0 10 | end 11 | } 12 | } 13 | puts ary[-2] + ary[-boy - 1] 14 | -------------------------------------------------------------------------------- /ja_JP/q57_03.rb: -------------------------------------------------------------------------------- 1 | # 縦線と横線 2 | @v, @h = 7, 10 3 | 4 | # 再帰的に横線を作成 5 | def make_bars(v, h) 6 | new_h = Array.new(h.size + v - 1, 0) 7 | # 各横線のパターン数をカウント 8 | v.times{|i| 9 | h.each_with_index{|cnt, j| 10 | new_h[i+j] += cnt 11 | } 12 | } 13 | if v == @v + 1 then 14 | puts h[@h] 15 | else 16 | make_bars(v + 1, new_h) 17 | end 18 | end 19 | make_bars(1, [1]) 20 | -------------------------------------------------------------------------------- /zh_CN/q09_01.rb: -------------------------------------------------------------------------------- 1 | boy, girl = 20, 10 2 | boy, girl = boy + 1, girl + 1 3 | ary = Array.new(boy * girl){0} 4 | ary[0] = 1 5 | girl.times{|g| 6 | boy.times{|b| 7 | if (b != g) && (boy - b != girl - g) then 8 | ary[b + boy * g] += ary[b - 1 + boy * g] if b > 0 9 | ary[b + boy * g] += ary[b + boy * (g - 1)] if g > 0 10 | end 11 | } 12 | } 13 | puts ary[-2] + ary[-boy - 1] 14 | -------------------------------------------------------------------------------- /ja_JP/q15_01.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 階段の段数 2 | STEPS = 4 # 一気に進める段数 3 | 4 | def move(a, b) 5 | return 0 if a > b # AさんがBさんよりも上になれば終了 6 | return 1 if a == b # 同じ段に止まればカウント 7 | cnt = 0 8 | (1..STEPS).each{|da| 9 | (1..STEPS).each{|db| 10 | cnt += move(a + da, b - db) # 再帰的に探索 11 | } 12 | } 13 | cnt 14 | end 15 | 16 | # Aさんは0の位置から、BさんはNの位置からスタート 17 | puts move(0, N) 18 | -------------------------------------------------------------------------------- /ja_JP/q36_01.rb: -------------------------------------------------------------------------------- 1 | n = (1..50).select{|i| (i % 2 > 0) || (i % 5 > 0)} 2 | answer = Array.new 3 | k = 1 4 | while (n.size > 0) do 5 | x = k.to_s(2).to_i * 7 6 | if x.to_s.include?('0') then 7 | n.each{|i| 8 | if x % i == 0 then 9 | answer << i if x.to_s == x.to_s.reverse 10 | n.delete(i) 11 | end 12 | } 13 | end 14 | k += 1 15 | end 16 | puts answer.sort 17 | -------------------------------------------------------------------------------- /zh_CN/q20_01.rb: -------------------------------------------------------------------------------- 1 | # 把魔方阵保存到数组 2 | magic_square = [1, 14, 14, 4, 11, 7, 6, 9, 3 | 8, 10, 10, 5, 13, 2, 3, 15] 4 | 5 | # 统计用哈希表 6 | sum = Hash.new(0) 7 | 1.upto(magic_square.size){|i| 8 | # 对组合进行全量检索 9 | magic_square.combination(i){|set| 10 | # 把组合的和值统计保存到哈希表 11 | sum[set.inject(:+)] += 1 12 | } 13 | } 14 | 15 | # 输出出现次数最多的和值 16 | puts sum.max{|x, y| x[1] <=> y[1]} 17 | -------------------------------------------------------------------------------- /zh_CN/q35_01.rb: -------------------------------------------------------------------------------- 1 | n = (1..50).select{|i| (i % 2 > 0) || (i % 5 > 0)} 2 | answer = Array.new 3 | k = 1 4 | while (n.size > 0) do 5 | x = k.to_s(2).to_i * 7 6 | if x.to_s.include?('0') then 7 | n.each{|i| 8 | if x % i == 0 then 9 | answer << i if x.to_s == x.to_s.reverse 10 | n.delete(i) 11 | end 12 | } 13 | end 14 | k += 1 15 | end 16 | puts answer.sort 17 | -------------------------------------------------------------------------------- /ja_JP/q20_01.rb: -------------------------------------------------------------------------------- 1 | # 魔方陣を配列にセット 2 | magic_square = [1, 14, 14, 4, 11, 7, 6, 9, 3 | 8, 10, 10, 5, 13, 2, 3, 15] 4 | 5 | # 集計用のハッシュ 6 | sum = Hash.new(0) 7 | 1.upto(magic_square.size){|i| 8 | # 組み合わせを全探索 9 | magic_square.combination(i){|set| 10 | # 組み合わせの合計をハッシュに格納 11 | sum[set.inject(:+)] += 1 12 | } 13 | } 14 | 15 | # 合計が最大のものを出力 16 | puts sum.max{|x, y| x[1] <=> y[1]} 17 | -------------------------------------------------------------------------------- /zh_CN/q28_01.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | N = 150 4 | 5 | max = 0 6 | # 按顺序选择社团 7 | 1.upto(club.size){|i| 8 | club.combination(i){|ary| 9 | # 已选择社团人数满足条件时 10 | if ary.map{|i| i[1]}.inject(:+) <= N then 11 | max = [ary.map{|i| i[0]}.inject(:+), max].max 12 | end 13 | } 14 | } 15 | 16 | puts max 17 | -------------------------------------------------------------------------------- /ja_JP/q08_01.rb: -------------------------------------------------------------------------------- 1 | N = 12 2 | 3 | def move(log) 4 | # 最初の位置を含んで、N+1個調べれば終了 5 | return 1 if log.size == N + 1 6 | 7 | cnt = 0 8 | # 前後左右に移動 9 | [[0, 1], [0, -1], [1, 0], [-1, 0]].each{|d| 10 | next_pos = [log[-1][0] + d[0], log[-1][1] + d[1]] 11 | # 探索済みでなければ移動させる 12 | if !log.include?(next_pos) then 13 | cnt += move(log + [next_pos]) 14 | end 15 | } 16 | cnt 17 | end 18 | 19 | puts move([[0, 0]]) 20 | -------------------------------------------------------------------------------- /zh_CN/q08_01.rb: -------------------------------------------------------------------------------- 1 | N = 12 2 | 3 | def move(log) 4 | # 包含最初位置,一共搜索N + 1次 5 | return 1 if log.size == N + 1 6 | 7 | cnt = 0 8 | # 前后左右移动 9 | [[0, 1], [0, -1], [1, 0], [-1, 0]].each{|d| 10 | next_pos = [log[-1][0] + d[0], log[-1][1] + d[1]] 11 | # 如果前方是没有搜索过的点,则可以前进 12 | if !log.include?(next_pos) then 13 | cnt += move(log + [next_pos]) 14 | end 15 | } 16 | cnt 17 | end 18 | 19 | puts move([[0, 0]]) 20 | -------------------------------------------------------------------------------- /zh_CN/q20_02.rb: -------------------------------------------------------------------------------- 1 | # 把魔方阵保存到数组 2 | magic_square = [1, 14, 14, 4, 11, 7, 6, 9, 3 | 8, 10, 10, 5, 13, 2, 3, 15] 4 | sum_all = magic_square.inject(:+) 5 | 6 | # 统计用哈希表 7 | sum = Array.new(sum_all + 1){0} 8 | # 初始值(没有加任何值时) 9 | sum[0] = 1 10 | magic_square.each{|n| 11 | # 从大数开始按顺序做加法 12 | (sum_all - n).downto(0).each{|i| 13 | sum[i + n] += sum[i] 14 | } 15 | } 16 | 17 | # 输出出现次数最多的和值 18 | puts sum.find_index(sum.max) 19 | -------------------------------------------------------------------------------- /ja_JP/q28_01.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | N = 150 4 | 5 | max = 0 6 | # 選択するクラブの数を順に試す 7 | 1.upto(club.size){|i| 8 | club.combination(i){|ary| 9 | # 選択したクラブで部員数の和が条件を満たすとき 10 | if ary.map{|i| i[1]}.inject(:+) <= N then 11 | max = [ary.map{|i| i[0]}.inject(:+), max].max 12 | end 13 | } 14 | } 15 | 16 | puts max 17 | -------------------------------------------------------------------------------- /ja_JP/q20_02.rb: -------------------------------------------------------------------------------- 1 | # 魔方陣を配列にセット 2 | magic_square = [1, 14, 14, 4, 11, 7, 6, 9, 3 | 8, 10, 10, 5, 13, 2, 3, 15] 4 | sum_all = magic_square.inject(:+) 5 | 6 | # 集計用のハッシュ 7 | sum = Array.new(sum_all + 1){0} 8 | # 初期値(何も足さないときが1個) 9 | sum[0] = 1 10 | magic_square.each{|n| 11 | # 大きい方から順に加算 12 | (sum_all - n).downto(0).each{|i| 13 | sum[i + n] += sum[i] 14 | } 15 | } 16 | 17 | # 合計が最大のものを出力 18 | puts sum.find_index(sum.max) 19 | -------------------------------------------------------------------------------- /ja_JP/q42_02.rb: -------------------------------------------------------------------------------- 1 | @found = false 2 | @op = ['+', '-', '*', '/', ''] 3 | def check(n, expr, num) 4 | if n == 0 then 5 | if eval(expr) == 1234 then 6 | puts expr 7 | @found = true 8 | end 9 | else 10 | @op.each{|i| 11 | check(n - 1, "#{expr}#{i}#{num}", num) 12 | } 13 | end 14 | end 15 | len = 1 16 | while !@found do 17 | (1..9).to_a.each{|num| 18 | check(len, num, num) 19 | } 20 | len += 1 21 | end 22 | -------------------------------------------------------------------------------- /zh_CN/q41_02.rb: -------------------------------------------------------------------------------- 1 | @found = false 2 | @op = ['+', '-', '*', '/', ''] 3 | def check(n, expr, num) 4 | if n == 0 then 5 | if eval(expr) == 1234 then 6 | puts expr 7 | @found = true 8 | end 9 | else 10 | @op.each{|i| 11 | check(n - 1, "#{expr}#{i}#{num}", num) 12 | } 13 | end 14 | end 15 | len = 1 16 | while !@found do 17 | (1..9).to_a.each{|num| 18 | check(len, num, num) 19 | } 20 | len += 1 21 | end 22 | -------------------------------------------------------------------------------- /zh_CN/q56_02.rb: -------------------------------------------------------------------------------- 1 | # 竖线和横线 2 | v, h = 7, 10 3 | total = 0 4 | # 对所有“下方的数字”排列,计算横线数目 5 | (1..v).to_a.permutation.each{|final| 6 | start = (1..v).to_a 7 | cnt = 0 8 | v.times{|i| 9 | # 找出对应“上方的数字”的位置 10 | move = start.index(final[i]) 11 | if move > 0 then 12 | # 更换“上方的数字” 13 | start[i], start[move] = start[move], start[i] 14 | cnt += move - i 15 | end 16 | } 17 | total += 1 if cnt == h 18 | } 19 | puts total 20 | -------------------------------------------------------------------------------- /ja_JP/q12_01.rb: -------------------------------------------------------------------------------- 1 | # 整数部分を含む場合 2 | i = 1 3 | while i += 1 4 | # 小数点を除去し、左から10文字を取得 5 | str = ('%10.10f'%Math.sqrt(i)).sub('.','')[0..9] 6 | # 重複を取り除いて10文字なら終了 7 | break if str.split('').uniq.length == 10 8 | end 9 | puts i 10 | 11 | # 小数部分のみの場合 12 | i = 1 13 | while i += 1 14 | # 小数点で分割し、小数部分のみを取得 15 | str = ('%10.10f'%Math.sqrt(i)).split('.')[1] 16 | # 小数部分の重複を取り除いて10文字なら終了 17 | break if str.split('').uniq.length == 10 18 | end 19 | puts i 20 | -------------------------------------------------------------------------------- /ja_JP/q57_02.rb: -------------------------------------------------------------------------------- 1 | # 縦線と横線 2 | v, h = 7, 10 3 | total = 0 4 | # 「下の数」の順列について、横線の数を調査 5 | (1..v).to_a.permutation.each{|final| 6 | start = (1..v).to_a 7 | cnt = 0 8 | v.times{|i| 9 | # 「上の数」のどの位置にあるかを調べる 10 | move = start.index(final[i]) 11 | if move > 0 then 12 | # 「上の数」を入れ替え 13 | start[i], start[move] = start[move], start[i] 14 | cnt += move - i 15 | end 16 | } 17 | total += 1 if cnt == h 18 | } 19 | puts total 20 | -------------------------------------------------------------------------------- /zh_CN/q12_01.rb: -------------------------------------------------------------------------------- 1 | # 含有整数部分的情况 2 | i = 1 3 | while i += 1 4 | # 去除小数点,从左往右取10个字符 5 | str = ('%10.10f'%Math.sqrt(i)).sub('.','')[0..9] 6 | # 如果包含不重复的10个字符,则结束循环 7 | break if str.split('').uniq.length == 10 8 | end 9 | puts i 10 | 11 | # 只看小数部分的情况 12 | i = 1 13 | while i += 1 14 | # 以小数点为界,只取小数部分 15 | str = ('%10.10f'%Math.sqrt(i)).split('.')[1] 16 | # 如果小数部分包含不重复的10个字符,则结束循环 17 | break if str.split('').uniq.length == 10 18 | end 19 | puts i 20 | -------------------------------------------------------------------------------- /ja_JP/q41_02.rb: -------------------------------------------------------------------------------- 1 | val = [] 2 | 256.times{|i| 3 | # 0〜255で反転 4 | rev = ('%08b'%i).reverse.to_i(2) 5 | 6 | if i < rev then 7 | s = i.to_s + rev.to_s 8 | # 0〜9が重複しない数字であれば対象とする 9 | val.push([i, rev]) if s.split('').uniq.size == s.length 10 | end 11 | } 12 | 13 | ip = [] 14 | val.combination(2){|a, b| 15 | # 0〜9を一度ずつ使っていればペアとする 16 | ip.push([a, b]) if (a + b).join.split('').uniq.size == 10 17 | } 18 | # ペアの組み合わせ数を出力 19 | puts ip.size * 8 20 | -------------------------------------------------------------------------------- /zh_CN/q40_02.rb: -------------------------------------------------------------------------------- 1 | val = [] 2 | 256.times{|i| 3 | # 反转0~255 4 | rev = ('%08b'%i).reverse.to_i(2) 5 | 6 | if i < rev then 7 | s = i.to_s + rev.to_s 8 | # 如果使用了0~9这10个数字个一次,就符合条件 9 | val.push([i, rev]) if s.split('').uniq.size == s.length 10 | end 11 | } 12 | 13 | ip = [] 14 | val.combination(2){|a, b| 15 | # 使用了0~9这10个数字个一次,就形成分组 16 | ip.push([a, b]) if (a + b).join.split('').uniq.size == 10 17 | } 18 | # 组合各分组输出结果 19 | puts ip.size * 8 20 | -------------------------------------------------------------------------------- /zh_CN/q21_01.rb: -------------------------------------------------------------------------------- 1 | count = 0 # “0”出现的次数 2 | line = 1 # 当前行的行数 3 | row = [1] # 当前行的值 4 | 5 | while count < 2014 do 6 | next_row = [1] 7 | # 通过上一行计算异或得到下一行 8 | (row.size - 1).times{|i| 9 | cell = row[i] ^ row[i + 1] 10 | next_row.push(cell) 11 | count += 1 if cell == 0 # 统计“0”出现的次数 12 | } 13 | next_row.push(1) 14 | line += 1 # 增加行数,进入下一行处理 15 | row = next_row 16 | end 17 | 18 | puts line # 统计到2014个“0”时的行 19 | -------------------------------------------------------------------------------- /zh_CN/q36_02.rb: -------------------------------------------------------------------------------- 1 | # 获取下一个数字序列 2 | def next_dice(dice) 3 | top = dice.div(6**5) 4 | left, right = dice.divmod(6**(5 - top)) 5 | (right + 1) * (6**(top + 1)) - (left + 1) 6 | end 7 | 8 | count = 0 9 | (6**6).times{|i| 10 | check = Array.new 11 | 12 | # 找下一个序列直到进入循环 13 | while !check.include?(i) do 14 | check << i 15 | i = next_dice(i) 16 | end 17 | 18 | # 定位循环位置,如果在循环范围外,则计数 19 | count += 1 if check.index(i) != 0 20 | } 21 | puts count 22 | -------------------------------------------------------------------------------- /ja_JP/q02_02.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 電卓 6 | 7 | 8 |
9 | 10 | 11 |
12 |
13 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /ja_JP/q21_01.rb: -------------------------------------------------------------------------------- 1 | count = 0 # 「0」が出現した回数 2 | line = 1 # 現在の行数 3 | row = [1] # 現在の行の値 4 | 5 | while count < 2014 do 6 | next_row = [1] 7 | # 前行から排他的論理和で次の行をセット 8 | (row.size - 1).times{|i| 9 | cell = row[i] ^ row[i + 1] 10 | next_row.push(cell) 11 | count += 1 if cell == 0 # 「0」の場合にカウント 12 | } 13 | next_row.push(1) 14 | line += 1 # 行数を増やして次の行へ 15 | row = next_row 16 | end 17 | 18 | puts line # 2014個カウントした行を出力 19 | -------------------------------------------------------------------------------- /zh_CN/q01_02.js: -------------------------------------------------------------------------------- 1 | /* 为字符串类型添加返回逆序字符串的方法 */ 2 | String.prototype.reverse = function (){ 3 | return this.split("").reverse().join(""); 4 | } 5 | 6 | /* 从11开始检索 */ 7 | var num = 11; 8 | while (true){ 9 | if ((num.toString() == num.toString().reverse()) && 10 | (num.toString(8) == num.toString(8).reverse()) && 11 | (num.toString(2) == num.toString(2).reverse())){ 12 | console.log(num); 13 | break; 14 | } 15 | /* 只检索奇数,每次加2 */ 16 | num += 2; 17 | } 18 | -------------------------------------------------------------------------------- /zh_CN/q02_02.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 计算器 6 | 7 | 8 |
9 | 10 | 11 |
12 |
13 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /zh_CN/q15_03.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 楼梯级数 2 | STEPS = 4 # 一次最大前进级数 3 | 4 | dp = Array.new(N + 1, 0) # 统计t次移动后的位置 5 | cnt = 0 6 | dp[N] = 1 # 设置初始值 7 | 8 | N.times{|i| # 移动次数(最大N) 9 | (N + 1).times{|j| # 移动的位置 10 | (1..STEPS).each{|k| 11 | break if k > j 12 | dp[j - k] += dp[j] 13 | } 14 | dp[j] = 0 # 清除移动位置 15 | } 16 | cnt += dp[0] if i % 2 == 1 # 经过偶数次移动到达相反位置 17 | } 18 | puts cnt 19 | -------------------------------------------------------------------------------- /zh_CN/q53_03.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | @memo = {} 3 | 4 | def search(cards, num) 5 | return 1 if num == 0 6 | return @memo[cards] if @memo.has_key?(cards) 7 | 8 | # 利用位运算设置包夹位置 9 | mask = (1 << (num + 1)) + 1 10 | count = 0 11 | while mask < (1 << (N * 2)) do 12 | # 如果可以放置,则递归地搜索 13 | count += search(cards | mask, num - 1) if cards & mask == 0 14 | # 包夹位置移动一位 15 | mask <<= 1 16 | end 17 | @memo[cards] = count 18 | end 19 | 20 | puts search(0, N) 21 | -------------------------------------------------------------------------------- /ja_JP/q37_02.rb: -------------------------------------------------------------------------------- 1 | # 次の目を取得する 2 | def next_dice(dice) 3 | top = dice.div(6**5) 4 | left, right = dice.divmod(6**(5 - top)) 5 | (right + 1) * (6**(top + 1)) - (left + 1) 6 | end 7 | 8 | count = 0 9 | (6**6).times{|i| 10 | check = Array.new 11 | 12 | # ループするまで次のサイコロを探す 13 | while !check.include?(i) do 14 | check << i 15 | i = next_dice(i) 16 | end 17 | 18 | # ループした位置をチェックし、ループ対象外であればカウント 19 | count += 1 if check.index(i) != 0 20 | } 21 | puts count 22 | -------------------------------------------------------------------------------- /ja_JP/q54_03.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | @memo = {} 3 | 4 | def search(cards, num) 5 | return 1 if num == 0 6 | return @memo[cards] if @memo.has_key?(cards) 7 | 8 | # ビット演算で挟む位置を設定 9 | mask = (1 << (num + 1)) + 1 10 | count = 0 11 | while mask < (1 << (N * 2)) do 12 | # 配置可能であれば、再帰的に探索 13 | count += search(cards | mask, num - 1) if cards & mask == 0 14 | # 挟む位置を一桁移動 15 | mask <<= 1 16 | end 17 | @memo[cards] = count 18 | end 19 | 20 | puts search(0, N) 21 | -------------------------------------------------------------------------------- /ja_JP/q01_02.js: -------------------------------------------------------------------------------- 1 | /* 文字列型に逆順を返すメソッドを追加 */ 2 | String.prototype.reverse = function (){ 3 | return this.split("").reverse().join(""); 4 | } 5 | 6 | /* 11から探索開始 */ 7 | var num = 11; 8 | while (true){ 9 | if ((num.toString() == num.toString().reverse()) && 10 | (num.toString(8) == num.toString(8).reverse()) && 11 | (num.toString(2) == num.toString(2).reverse())){ 12 | console.log(num); 13 | break; 14 | } 15 | /* 奇数だけを探すため、2つずつ増やす */ 16 | num += 2; 17 | } 18 | -------------------------------------------------------------------------------- /ja_JP/q15_03.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 階段の段数 2 | STEPS = 4 # 一気に進める段数 3 | 4 | dp = Array.new(N + 1, 0) # t回の移動で移動した位置を集計 5 | cnt = 0 6 | dp[N] = 1 # 初期値をセット 7 | 8 | N.times{|i| # 移動回数(最大N) 9 | (N + 1).times{|j| # 移動元の段 10 | (1..STEPS).each{|k| 11 | break if k > j 12 | dp[j - k] += dp[j] 13 | } 14 | dp[j] = 0 # 移動元はクリア 15 | } 16 | cnt += dp[0] if i % 2 == 1 # 偶数回の移動で逆に到着 17 | } 18 | puts cnt 19 | -------------------------------------------------------------------------------- /ja_JP/q05_01.rb: -------------------------------------------------------------------------------- 1 | cnt = 0 2 | (0..2).each{|coin500| # 500円玉は最大2枚 3 | (0..10).each{|coin100| # 100円玉は最大10枚 4 | (0..15).each{|coin50| # 50円玉は最大15枚 5 | (0..15).each{|coin10| # 10円玉は最大15枚 6 | if coin500 + coin100 + coin50 + coin10 <= 15 then 7 | if coin500 * 500 + coin100 * 100 + 8 | coin50 * 50 + coin10 * 10 == 1000 then 9 | cnt += 1 10 | end 11 | end 12 | } 13 | } 14 | } 15 | } 16 | puts cnt 17 | -------------------------------------------------------------------------------- /ja_JP/q33_01.rb: -------------------------------------------------------------------------------- 1 | # 集計フィールド 2 | @count = 0 3 | 4 | # 再帰的に検索 5 | def search(list, len) 6 | if list.length == 1 then # 一意に識別できたとき 7 | @count += len - 1 8 | else 9 | # 複数存在するとき、1文字増やして調査 10 | list.uniq{|x| x[0, len]}.each{|k| 11 | search(list.select{|x| x.start_with?(k[0, len])}, len + 1) 12 | } 13 | end 14 | end 15 | 16 | # CSVファイルから「かな」の列を配列にセットし、転置 17 | $<.drop(1).map{|e| e.split(',')[3,2]}.transpose.each{|ku| 18 | search(ku, 1) 19 | } 20 | puts @count 21 | -------------------------------------------------------------------------------- /ja_JP/q51_01.rb: -------------------------------------------------------------------------------- 1 | def shuffle(card) 2 | left = card.take(card.size / 2) 3 | right = card.drop(card.size / 2) 4 | result = [] 5 | left.size.times{|i| 6 | result.push(left[i]) 7 | result.push(right[i]) 8 | } 9 | result 10 | end 11 | 12 | count = 0 13 | 14 | (1..100).each{|n| 15 | init = (1..(2 * n)).to_a 16 | card = init.clone 17 | (2 * (n - 1)).times{|i| 18 | card = shuffle(card) 19 | } 20 | count += 1 if card == init 21 | } 22 | 23 | puts count 24 | -------------------------------------------------------------------------------- /ja_JP/q13_01.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (0..9).to_a.permutation do |r, e, a, d, w, i, t, l, k, s| 3 | next if r == 0 or w == 0 or t == 0 or s == 0 4 | read = r * 1000 + e * 100 + a * 10 + d 5 | write = w * 10000 + r * 1000 + i * 100 + t * 10 + e 6 | talk = t * 1000 + a * 100 + l * 10 + k 7 | skill = s * 10000 + k * 1000 + i * 100 + l * 10 + l 8 | if read + write + talk == skill then 9 | count += 1 10 | puts "#{read} + #{write} + #{talk} = #{skill}" 11 | end 12 | end 13 | puts count 14 | -------------------------------------------------------------------------------- /zh_CN/q05_01.rb: -------------------------------------------------------------------------------- 1 | cnt = 0 2 | (0..2).each{|coin500| # 500日元硬币最多2枚 3 | (0..10).each{|coin100| # 100日元硬币最多10枚 4 | (0..15).each{|coin50| # 50日元硬币最多15枚 5 | (0..15).each{|coin10| # 10日元硬币最多15枚 6 | if coin500 + coin100 + coin50 + coin10 <= 15 then 7 | if coin500 * 500 + coin100 * 100 + 8 | coin50 * 50 + coin10 * 10 == 1000 then 9 | cnt += 1 10 | end 11 | end 12 | } 13 | } 14 | } 15 | } 16 | puts cnt 17 | -------------------------------------------------------------------------------- /zh_CN/q13_01.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (0..9).to_a.permutation do |r, e, a, d, w, i, t, l, k, s| 3 | next if r == 0 or w == 0 or t == 0 or s == 0 4 | read = r * 1000 + e * 100 + a * 10 + d 5 | write = w * 10000 + r * 1000 + i * 100 + t * 10 + e 6 | talk = t * 1000 + a * 100 + l * 10 + k 7 | skill = s * 10000 + k * 1000 + i * 100 + l * 10 + l 8 | if read + write + talk == skill then 9 | count += 1 10 | puts "#{read} + #{write} + #{talk} = #{skill}" 11 | end 12 | end 13 | puts count 14 | -------------------------------------------------------------------------------- /ja_JP/q07_02.rb: -------------------------------------------------------------------------------- 1 | # 日付を扱うDateクラスを読込 2 | require 'date' 3 | 4 | # 対象の期間で、2進数の5文字目から8文字を抽出 5 | from_left = 19641010.to_s(2)[4,8].to_i(2) 6 | to_left = 20200724.to_s(2)[4,8].to_i(2) 7 | # 左右の8文字をループ 8 | from_left.upto(to_left){|i| 9 | l = "%08b" % i # 左側 10 | r = l.reverse # 右側 11 | (0..1).each{|m| # 中央 12 | value = "1001#{l}#{m}#{r}1001" 13 | begin 14 | puts Date.parse(value.to_i(2).to_s).strftime('%Y%m%d') 15 | rescue # 有効な日付以外は無視 16 | end 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ja_JP/q40_01.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | if cards[0] == 1 then 7 | if @max < depth then 8 | @max = depth 9 | @max_list.clear 10 | end 11 | @max_list[init] = cards if @max == depth 12 | else 13 | solve(cards[0..(cards[0] - 1)].reverse + cards[cards[0]..N], 14 | init, depth + 1) 15 | end 16 | end 17 | 18 | (1..N).to_a.permutation.each{|i| solve(i, i, 0)} 19 | puts @max 20 | puts @max_list 21 | -------------------------------------------------------------------------------- /zh_CN/q07_02.rb: -------------------------------------------------------------------------------- 1 | # 读入处理日期的Date库 2 | require 'date' 3 | 4 | # 取出日期区间的二进制数的第5数位到第8数位的值。 5 | from_left = 19641010.to_s(2)[4,8].to_i(2) 6 | to_left = 20200724.to_s(2)[4,8].to_i(2) 7 | # 遍历左侧和右侧的8个数位 8 | from_left.upto(to_left){|i| 9 | l = "%08b" % i # 左侧 10 | r = l.reverse # 右侧 11 | (0..1).each{|m| # 中间 12 | value = "1001#{l}#{m}#{r}1001" 13 | begin 14 | puts Date.parse(value.to_i(2).to_s).strftime('%Y%m%d') 15 | rescue # 忽略无效日期 16 | end 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /zh_CN/q15_02.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 楼梯级数 2 | STEPS = 4 # 一次最大前进级数 3 | 4 | @memo = {} 5 | 6 | def move(a, b) 7 | return @memo[[a,b]] if @memo.has_key?([a, b]) 8 | return @memo[[a,b]] = 0 if a > b # 如果A级数比B大,则结束搜索 9 | return @memo[[a, b]] = 1 if a == b # 如果停在同一级,则算入结果 10 | cnt = 0 11 | (1..STEPS).each{|da| 12 | (1..STEPS).each{|db| 13 | cnt += move(a + da, b - db) # 递归搜索 14 | } 15 | } 16 | @memo[[a, b]] = cnt 17 | end 18 | 19 | # A从0位置开始,B从N位置开始 20 | puts move(0, N) 21 | -------------------------------------------------------------------------------- /zh_CN/q39_01.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | if cards[0] == 1 then 7 | if @max < depth then 8 | @max = depth 9 | @max_list.clear 10 | end 11 | @max_list[init] = cards if @max == depth 12 | else 13 | solve(cards[0..(cards[0] - 1)].reverse + cards[cards[0]..N], 14 | init, depth + 1) 15 | end 16 | end 17 | 18 | (1..N).to_a.permutation.each{|i| solve(i, i, 0)} 19 | puts @max 20 | puts @max_list 21 | -------------------------------------------------------------------------------- /zh_CN/q37_01.rb: -------------------------------------------------------------------------------- 1 | # 定义表示0〜9数字的比特序列 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 每次设置翻转比特序列的值为初始值 6 | min = 63 7 | 8 | # 在0~9组成的序列中,检索替换次数最少的序列 9 | (0..9).to_a.permutation.each{|seq| 10 | sum = 0 11 | (seq.size - 1).times{|j| 12 | # 执行异或运算,计算结果中1的个数 13 | sum += (bit[seq[j]]^bit[seq[j+1]]).to_s(2).count("1") 14 | break if min <= sum 15 | } 16 | min = sum if min > sum 17 | } 18 | puts min 19 | -------------------------------------------------------------------------------- /ja_JP/q15_02.rb: -------------------------------------------------------------------------------- 1 | N = 10 # 階段の段数 2 | STEPS = 4 # 一気に進める段数 3 | 4 | @memo = {} 5 | 6 | def move(a, b) 7 | return @memo[[a,b]] if @memo.has_key?([a, b]) 8 | return @memo[[a,b]] = 0 if a > b # AさんがBよりも上になれば終了 9 | return @memo[[a, b]] = 1 if a == b # 同じ段に止まればカウント 10 | cnt = 0 11 | (1..STEPS).each{|da| 12 | (1..STEPS).each{|db| 13 | cnt += move(a + da, b - db) # 再帰的に探索 14 | } 15 | } 16 | @memo[[a, b]] = cnt 17 | end 18 | 19 | # Aさんは0の位置から、BさんはNの位置からスタート 20 | puts move(0, N) 21 | -------------------------------------------------------------------------------- /ja_JP/q19_01.rb: -------------------------------------------------------------------------------- 1 | require 'prime' 2 | 3 | primes = Prime.take(6) # a〜fに当てはまる素数6個 4 | min = primes[-1] * primes[-1] # 最大でも一番大きいものの平方 5 | min_friend = [] 6 | 7 | primes.permutation{|prime| # 6個の素数の順列 8 | # 2つずつ選んで掛け算する 9 | friends = prime.each_cons(2).map{|x, y| x * y} 10 | # 先頭と末尾は同じ数の平方 11 | friends += [prime[0], prime[-1]].map{|x| x * x} 12 | if min > friends.max then # 最小を更新した場合 13 | min = friends.max 14 | min_friend = friends 15 | end 16 | } 17 | 18 | puts min 19 | p min_friend 20 | -------------------------------------------------------------------------------- /zh_CN/q19_01.rb: -------------------------------------------------------------------------------- 1 | require 'prime' 2 | 3 | primes = Prime.take(6) # 用6个质数充当a~f 4 | min = primes[-1] * primes[-1] # 把最小数字设置成最大质数的平方 5 | min_friend = [] 6 | 7 | primes.permutation{|prime| # 按顺序排列的6个质数 8 | # 按顺序选取2个数字做乘法 9 | friends = prime.each_cons(2).map{|x, y| x * y} 10 | # 开头和结尾的数字乘方 11 | friends += [prime[0], prime[-1]].map{|x| x * x} 12 | if min > friends.max then # 更新最小数字的情况 13 | min = friends.max 14 | min_friend = friends 15 | end 16 | } 17 | 18 | puts min 19 | p min_friend 20 | -------------------------------------------------------------------------------- /ja_JP/q28_02.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | N = 150 4 | 5 | area = Array.new(club.size + 1){Array.new(N + 1){0}} 6 | (club.size - 1).downto(0){|i| 7 | (N + 1).times{|j| 8 | if j < club[i][1] then 9 | area[i][j] = area[i + 1][j] 10 | else 11 | area[i][j] = [area[i + 1][j], 12 | area[i + 1][j - club[i][1]] + club[i][0]].max 13 | end 14 | } 15 | } 16 | puts area[0][N] 17 | -------------------------------------------------------------------------------- /ja_JP/q38_01.rb: -------------------------------------------------------------------------------- 1 | # 0〜9を表すビットを定義 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 毎回全ビットを反転させた値を初期値とする 6 | min = 63 7 | 8 | # 0〜9の順列について、より切替回数が少ないものを探索する 9 | (0..9).to_a.permutation.each{|seq| 10 | sum = 0 11 | (seq.size - 1).times{|j| 12 | # 排他的論理和を計算し、1が立っているビット数をカウント 13 | sum += (bit[seq[j]]^bit[seq[j+1]]).to_s(2).count("1") 14 | break if min <= sum 15 | } 16 | min = sum if min > sum 17 | } 18 | puts min 19 | -------------------------------------------------------------------------------- /zh_CN/q28_02.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | N = 150 4 | 5 | area = Array.new(club.size + 1){Array.new(N + 1){0}} 6 | (club.size - 1).downto(0){|i| 7 | (N + 1).times{|j| 8 | if j < club[i][1] then 9 | area[i][j] = area[i + 1][j] 10 | else 11 | area[i][j] = [area[i + 1][j], 12 | area[i + 1][j - club[i][1]] + club[i][0]].max 13 | end 14 | } 15 | } 16 | puts area[0][N] 17 | -------------------------------------------------------------------------------- /ja_JP/q28_03.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | 4 | @memo = {} 5 | def search(club, remain) 6 | return @memo[[club, remain]] if @memo.has_key?([club, remain]) 7 | max = 0 8 | club.each{|c| 9 | # クラブを追加する部員数の余裕がある場合 10 | if remain - c[1] >= 0 then 11 | max = [c[0] + search(club - [c], remain - c[1]), max].max 12 | end 13 | } 14 | @memo[[club, remain]] = max 15 | end 16 | 17 | puts search(club, 150) 18 | -------------------------------------------------------------------------------- /ja_JP/q54_02.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | cards = [0] * N * 2 3 | @count = 0 4 | 5 | def search(cards, num) 6 | if num == 0 then # 最後の判定を0に変更 7 | @count += 1 8 | else 9 | (2 * N - 1 - num).times{|i| 10 | if cards[i] == 0 && cards[i + num + 1] == 0 then 11 | cards[i], cards[i + num + 1] = num, num 12 | search(cards, num - 1) # 大きい方からなので減らす 13 | cards[i], cards[i + num + 1] = 0, 0 14 | end 15 | } 16 | end 17 | end 18 | 19 | search(cards, N) # 最初は最大のカードを配置 20 | puts @count 21 | -------------------------------------------------------------------------------- /zh_CN/q28_03.rb: -------------------------------------------------------------------------------- 1 | club = [[11000, 40], [8000, 30], [400, 24], [800, 20], [900, 14], 2 | [1800, 16], [1000, 15], [7000,40], [100, 10], [300, 12]] 3 | 4 | @memo = {} 5 | def search(club, remain) 6 | return @memo[[club, remain]] if @memo.has_key?([club, remain]) 7 | max = 0 8 | club.each{|c| 9 | # 如果剩余人数还足以选择新的社团 10 | if remain - c[1] >= 0 then 11 | max = [c[0] + search(club - [c], remain - c[1]), max].max 12 | end 13 | } 14 | @memo[[club, remain]] = max 15 | end 16 | 17 | puts search(club, 150) 18 | -------------------------------------------------------------------------------- /zh_CN/q53_02.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | cards = [0] * N * 2 3 | @count = 0 4 | 5 | def search(cards, num) 6 | if num == 0 then # 把终止判定改为0 7 | @count += 1 8 | else 9 | (2 * N - 1 - num).times{|i| 10 | if cards[i] == 0 && cards[i + num + 1] == 0 then 11 | cards[i], cards[i + num + 1] = num, num 12 | search(cards, num - 1) # 因为从较大的开始,所以这里是减法 13 | cards[i], cards[i + num + 1] = 0, 0 14 | end 15 | } 16 | end 17 | end 18 | 19 | search(cards, N) # 从最大的纸牌开始 20 | puts @count 21 | -------------------------------------------------------------------------------- /zh_CN/q56_04.js: -------------------------------------------------------------------------------- 1 | /* 竖线和横线 */ 2 | const V = 7, H = 10; 3 | 4 | /* 递归生成横线 */ 5 | function make_bars(v, h){ 6 | var new_h = new Array(h.length + v - 1); 7 | for (var i = 0; i < h.length + v - 1; i++){ 8 | new_h[i] = 0; 9 | } 10 | /* 统计各横线的情况 */ 11 | for (var i = 0; i < v; i++){ 12 | for (var j = 0; j < h.length; j++){ 13 | new_h[i + j] += h[j] 14 | } 15 | } 16 | if (v == V + 1){ 17 | console.log(h[H]); 18 | } else { 19 | make_bars(v + 1, new_h); 20 | } 21 | } 22 | 23 | make_bars(1, [1]); 24 | -------------------------------------------------------------------------------- /zh_CN/q24_01.rb: -------------------------------------------------------------------------------- 1 | # 列举能一次击落的2个靶子的组合 2 | board = [[1, 2], [2, 3], [7, 8], [8, 9], 3 | [1, 4], [3, 6], [4, 7], [6, 9]] 4 | # 增加逐个击落的方法 5 | 1.upto(9){|i| 6 | board.push([i]) 7 | } 8 | 9 | @memo = {[] => 1} 10 | def strike(board) 11 | # 如果已经全部遍历完,则输出这个值 12 | return @memo[board] if @memo.has_key?(board) 13 | cnt = 0 14 | board.each{|b| 15 | # 排除含有已经击落数字的组合 16 | next_board = board.select{|i| (b & i).size == 0} 17 | cnt += strike(next_board) 18 | } 19 | @memo[board] = cnt 20 | end 21 | 22 | puts strike(board) 23 | -------------------------------------------------------------------------------- /ja_JP/q51_02.rb: -------------------------------------------------------------------------------- 1 | def shuffle(card) 2 | left = card.take(card.size / 2) 3 | right = card.drop(card.size / 2) 4 | result = [] 5 | left.size.times{|i| 6 | result.push(left[i]) 7 | result.push(right[i]) 8 | } 9 | result 10 | end 11 | 12 | count = 0 13 | 14 | (1..100).each{|n| 15 | init = (1..(2 * n)).to_a 16 | card = init.clone 17 | i = 0 18 | while true do 19 | card = shuffle(card) 20 | i += 1 21 | break if card == init 22 | end 23 | count += 1 if i == 2 * (n - 1) 24 | } 25 | 26 | puts count 27 | -------------------------------------------------------------------------------- /ja_JP/q57_04.js: -------------------------------------------------------------------------------- 1 | /* 縦線と横線 */ 2 | const V = 7, H = 10; 3 | 4 | /* 再帰的に横線を作成 */ 5 | function make_bars(v, h){ 6 | var new_h = new Array(h.length + v - 1); 7 | for (var i = 0; i < h.length + v - 1; i++){ 8 | new_h[i] = 0; 9 | } 10 | /* 各横線のパターン数をカウント */ 11 | for (var i = 0; i < v; i++){ 12 | for (var j = 0; j < h.length; j++){ 13 | new_h[i + j] += h[j] 14 | } 15 | } 16 | if (v == V + 1){ 17 | console.log(h[H]); 18 | } else { 19 | make_bars(v + 1, new_h); 20 | } 21 | } 22 | 23 | make_bars(1, [1]); 24 | -------------------------------------------------------------------------------- /zh_CN/q50_02.rb: -------------------------------------------------------------------------------- 1 | def shuffle(card) 2 | left = card.take(card.size / 2) 3 | right = card.drop(card.size / 2) 4 | result = [] 5 | left.size.times{|i| 6 | result.push(left[i]) 7 | result.push(right[i]) 8 | } 9 | result 10 | end 11 | 12 | count = 0 13 | 14 | (1..100).each{|n| 15 | init = (1..(2 * n)).to_a 16 | card = init.clone 17 | i = 0 18 | while true do 19 | card = shuffle(card) 20 | i += 1 21 | break if card == init 22 | end 23 | count += 1 if i == 2 * (n - 1) 24 | } 25 | 26 | puts count 27 | -------------------------------------------------------------------------------- /ja_JP/q02_01.js: -------------------------------------------------------------------------------- 1 | var op = ["+", "-", "*", "/", ""]; 2 | for (i = 1000; i < 10000; i++){ 3 | var c = String(i); 4 | for (j = 0; j < op.length; j++){ 5 | for (k = 0; k < op.length; k++){ 6 | for (l = 0; l < op.length; l++){ 7 | val = c.charAt(3) + op[j] + c.charAt(2) + op[k] + 8 | c.charAt(1) + op[l] + c.charAt(0); 9 | if (val.length > 4){ /* 必ず1つは演算子を入れる */ 10 | if (i == eval(val)){ 11 | console.log(val + " = " + i); 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /zh_CN/q02_01.js: -------------------------------------------------------------------------------- 1 | var op = ["+", "-", "*", "/", ""]; 2 | for (i = 1000; i < 10000; i++){ 3 | var c = String(i); 4 | for (j = 0; j < op.length; j++){ 5 | for (k = 0; k < op.length; k++){ 6 | for (l = 0; l < op.length; l++){ 7 | val = c.charAt(3) + op[j] + c.charAt(2) + op[k] + 8 | c.charAt(1) + op[l] + c.charAt(0); 9 | if (val.length > 4){ /* 一定要插入1个运算符 */ 10 | if (i == eval(val)){ 11 | console.log(val + " = " + i); 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ja_JP/q13_02.rb: -------------------------------------------------------------------------------- 1 | expression = "READ+WRITE+TALK==SKILL" 2 | nums = expression.split(/[^a-zA-Z]/) 3 | chars = nums.join().split("").uniq 4 | head = nums.map{|num| num[0]} 5 | 6 | count = 0 7 | (0..9).to_a.permutation(chars.size){|seq| 8 | is_zero_first = false 9 | if seq.include?(0) then 10 | is_zero_first = head.include?(chars[seq.index(0)]) 11 | end 12 | if !is_zero_first then 13 | e = expression.tr(chars.join(), seq.join()) 14 | if eval(e) then 15 | puts e 16 | count += 1 17 | end 18 | end 19 | } 20 | puts count 21 | -------------------------------------------------------------------------------- /ja_JP/q24_01.rb: -------------------------------------------------------------------------------- 1 | # 2枚抜きの可能性がある抜き方をセット 2 | board = [[1, 2], [2, 3], [7, 8], [8, 9], 3 | [1, 4], [3, 6], [4, 7], [6, 9]] 4 | # 1枚ずつの抜き方を追加 5 | 1.upto(9){|i| 6 | board.push([i]) 7 | } 8 | 9 | @memo = {[] => 1} 10 | def strike(board) 11 | # すでに探索済みの場合はその値を使用 12 | return @memo[board] if @memo.has_key?(board) 13 | cnt = 0 14 | board.each{|b| 15 | # 抜いた的に含まれる数字がある抜き方は除外 16 | next_board = board.select{|i| (b & i).size == 0} 17 | cnt += strike(next_board) 18 | } 19 | @memo[board] = cnt 20 | end 21 | 22 | puts strike(board) 23 | -------------------------------------------------------------------------------- /ja_JP/q40_03.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | (1..(cards.size - 1)).each{|i| 7 | if i + 1 == cards[i] then 8 | solve(cards[0..i].reverse + cards[(i+1)..N], 9 | init, depth + 1) 10 | check = true 11 | end 12 | } 13 | if @max < depth then 14 | @max = depth 15 | @max_list.clear 16 | end 17 | @max_list[cards] = init if @max == depth 18 | end 19 | 20 | (2..N).to_a.permutation.each{|i| solve([1] + i, [1] + i, 0)} 21 | puts @max 22 | puts @max_list 23 | -------------------------------------------------------------------------------- /zh_CN/q13_02.rb: -------------------------------------------------------------------------------- 1 | expression = "READ+WRITE+TALK==SKILL" 2 | nums = expression.split(/[^a-zA-Z]/) 3 | chars = nums.join().split("").uniq 4 | head = nums.map{|num| num[0]} 5 | 6 | count = 0 7 | (0..9).to_a.permutation(chars.size){|seq| 8 | is_zero_first = false 9 | if seq.include?(0) then 10 | is_zero_first = head.include?(chars[seq.index(0)]) 11 | end 12 | if !is_zero_first then 13 | e = expression.tr(chars.join(), seq.join()) 14 | if eval(e) then 15 | puts e 16 | count += 1 17 | end 18 | end 19 | } 20 | puts count 21 | -------------------------------------------------------------------------------- /zh_CN/q39_03.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | (1..(cards.size - 1)).each{|i| 7 | if i + 1 == cards[i] then 8 | solve(cards[0..i].reverse + cards[(i+1)..N], 9 | init, depth + 1) 10 | check = true 11 | end 12 | } 13 | if @max < depth then 14 | @max = depth 15 | @max_list.clear 16 | end 17 | @max_list[cards] = init if @max == depth 18 | end 19 | 20 | (2..N).to_a.permutation.each{|i| solve([1] + i, [1] + i, 0)} 21 | puts @max 22 | puts @max_list 23 | -------------------------------------------------------------------------------- /zh_CN/q36_01.rb: -------------------------------------------------------------------------------- 1 | # 获取下一个数字序列 2 | def next_dice(dice) 3 | right = dice.slice!(0..(dice[0].to_i - 1)).tr('123456','654321') 4 | dice += right 5 | end 6 | 7 | count = 0 8 | (6**6).times{|i| 9 | # 用六进制数表示的话,只需加上“111111”就变为1~6之间了 10 | dice = (i.to_s(6).to_i + 111111).to_s 11 | check = Hash.new 12 | j = 0 13 | 14 | # 找下一个序列直到进入循环 15 | while !check.has_key?(dice) do 16 | check[dice] = j 17 | dice = next_dice(dice) 18 | j += 1 19 | end 20 | 21 | # 定位循环位置,如果在循环范围外,则计数 22 | count += 1 if check[dice] > 0 23 | } 24 | puts count 25 | -------------------------------------------------------------------------------- /ja_JP/q37_01.rb: -------------------------------------------------------------------------------- 1 | # 次の目を取得する 2 | def next_dice(dice) 3 | right = dice.slice!(0..(dice[0].to_i - 1)).tr('123456','654321') 4 | dice += right 5 | end 6 | 7 | count = 0 8 | (6**6).times{|i| 9 | # 6進数で表現して「111111」を加えることで1〜6にする 10 | dice = (i.to_s(6).to_i + 111111).to_s 11 | check = Hash.new 12 | j = 0 13 | 14 | # ループするまで次のサイコロを探す 15 | while !check.has_key?(dice) do 16 | check[dice] = j 17 | dice = next_dice(dice) 18 | j += 1 19 | end 20 | 21 | # ループした位置をチェックし、ループ対象外であればカウント 22 | count += 1 if check[dice] > 0 23 | } 24 | puts count 25 | -------------------------------------------------------------------------------- /ja_JP/q31_02.js: -------------------------------------------------------------------------------- 1 | function route(width, height, back_y){ 2 | if (width == 1) return (back_y == height) ? back_y : back_y + 2; 3 | if (height == 1) return (back_y == 0) ? 2 : 1; 4 | var total = 0; 5 | if (back_y == 0){ 6 | for (var i = 0; i < height; i++){ 7 | total += 2 * route(width - 1, height, i + 1); 8 | } 9 | } else { 10 | for (var i = back_y; i <= height; i++){ 11 | total += route(width - 1, height, i); 12 | } 13 | total += route(width, height - 1, back_y - 1); 14 | } 15 | return total; 16 | } 17 | console.log(route(6, 6, 0)); 18 | -------------------------------------------------------------------------------- /zh_CN/q31_02.js: -------------------------------------------------------------------------------- 1 | function route(width, height, back_y){ 2 | if (width == 1) return (back_y == height) ? back_y : back_y + 2; 3 | if (height == 1) return (back_y == 0) ? 2 : 1; 4 | var total = 0; 5 | if (back_y == 0){ 6 | for (var i = 0; i < height; i++){ 7 | total += 2 * route(width - 1, height, i + 1); 8 | } 9 | } else { 10 | for (var i = back_y; i <= height; i++){ 11 | total += route(width - 1, height, i); 12 | } 13 | total += route(width, height - 1, back_y - 1); 14 | } 15 | return total; 16 | } 17 | console.log(route(6, 6, 0)); 18 | -------------------------------------------------------------------------------- /zh_CN/q46_01.rb: -------------------------------------------------------------------------------- 1 | N = 4 2 | @count = Hash.new(0) 3 | 4 | def search() 5 | # 把各行设置为数值 6 | (0..(2**N-1)).to_a.repeated_permutation(N).each{|rows| 7 | # 计算各列○的个数 8 | col_count = Array.new(N, 0) 9 | N.times{|c| 10 | rows.each{|r| 11 | col_count[c] += 1 if (r & (1 << c) > 0) 12 | } 13 | } 14 | # 计算各行○的个数 15 | row_count = rows.map{|r| r.to_s(2).count("1")} 16 | # 用哈希表记录行和列组合的出现次数 17 | @count[row_count + col_count] += 1 18 | } 19 | end 20 | 21 | search() 22 | # 输出只出现一次的组合 23 | puts @count.select{|k, v| v == 1}.count 24 | -------------------------------------------------------------------------------- /zh_CN/q42_02.rb: -------------------------------------------------------------------------------- 1 | n = 5 2 | 3 | # 顺序搜索的初始值 4 | fw = [(1..n*2).to_a] 5 | # 逆序搜索的初始值 6 | bw = [(1..n*2).to_a.reverse] 7 | 8 | depth = 1 9 | while true do 10 | # 顺序搜索 11 | fw = fw.each_with_object([]) do |c, result| 12 | 1.upto(n){|i| result << c[i, n] + c[0, i] + c[i + n..-1]} 13 | end 14 | break if (fw & bw).size > 0 15 | depth += 1 16 | 17 | # 逆序搜索 18 | bw = bw.each_with_object([]) do |c, result| 19 | 1.upto(n){|i| result << c[n, i] + c[0, n] + c[i + n..-1]} 20 | end 21 | break if (fw & bw).size > 0 22 | depth += 1 23 | end 24 | 25 | puts depth 26 | -------------------------------------------------------------------------------- /zh_CN/q48_01.rb: -------------------------------------------------------------------------------- 1 | N = 8 # 各色卡片数目 2 | start = (1 << N) - 1 # 开始状态(0N个,1N个) 3 | mask = (1 << N * 2) - 1 # 掩码 4 | 5 | # 目标状态(0和1交错排列) 6 | goal1 = 0 7 | N.times{|i| goal1 = (goal1 << 2) + 1} 8 | goal2 = mask - goal1 9 | 10 | # 反转次数 11 | count = N * 2 12 | (1 << N*2).times{|i| # 表示开始反转位置的比特列 13 | turn = i ^ (i << 1) ^ (i << 2) 14 | turn = (turn ^ (turn >> (N * 2))) & mask 15 | 16 | # 到达目标状态后找出反转位置数字的最小值 17 | if (start ^ turn == goal1) || (start ^ turn == goal2) then 18 | count = [count, i.to_s(2).count('1')].min 19 | end 20 | } 21 | puts count 22 | -------------------------------------------------------------------------------- /ja_JP/q47_01.rb: -------------------------------------------------------------------------------- 1 | N = 4 2 | @count = Hash.new(0) 3 | 4 | def search() 5 | # 各行を数値としてセット 6 | (0..(2**N-1)).to_a.repeated_permutation(N).each{|rows| 7 | # 各列の「○」の数をカウント 8 | col_count = Array.new(N, 0) 9 | N.times{|c| 10 | rows.each{|r| 11 | col_count[c] += 1 if (r & (1 << c) > 0) 12 | } 13 | } 14 | # 各行の「○」の数をカウント 15 | row_count = rows.map{|r| r.to_s(2).count("1")} 16 | # ハッシュに行と列のカウントで集計 17 | @count[row_count + col_count] += 1 18 | } 19 | end 20 | 21 | search() 22 | # 1通りに配置できるものを出力 23 | puts @count.select{|k, v| v == 1}.count 24 | -------------------------------------------------------------------------------- /zh_CN/q45_01.rb: -------------------------------------------------------------------------------- 1 | N = 7 2 | checked = {(1..N).to_a => 0} # 已检查的数组 3 | check = [(1..N).to_a] # 检查目标 4 | depth = 0 # 交换次数 5 | 6 | while check.size > 0 do # 如果存在检查目标,则循环 7 | next_check = [] 8 | (0..(N-1)).to_a.combination(2){|i, j| # 选择两个数字交换 9 | check.each{|c| 10 | d = c.clone 11 | d[i], d[j] = d[j], d[i] 12 | if !checked.has_key?(d) then 13 | checked[d] = depth + 1 14 | next_check << d 15 | end 16 | } 17 | } 18 | check = next_check 19 | depth += 1 20 | end 21 | 22 | puts checked.values.inject(:+) 23 | -------------------------------------------------------------------------------- /zh_CN/q53_01.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | cards = [0] * N * 2 # 纸牌初始值 3 | @count = 0 4 | 5 | def search(cards, num) 6 | if num == N + 1 then # 放置到最后时处理成功 7 | @count += 1 8 | else 9 | # 检查是否能放置,按顺序处理 10 | (2 * N - 1 - num).times{|i| 11 | if cards[i] == 0 && cards[i + num + 1] == 0 then 12 | # 能放置的话就放置纸牌,递归搜索下一步 13 | cards[i], cards[i + num + 1] = num, num 14 | search(cards, num + 1) 15 | cards[i], cards[i + num + 1] = 0, 0 16 | end 17 | } 18 | end 19 | end 20 | 21 | search(cards, 1) # 最开始放置标记为“1”的纸牌 22 | puts @count 23 | -------------------------------------------------------------------------------- /ja_JP/q43_02.rb: -------------------------------------------------------------------------------- 1 | n = 5 2 | 3 | # 順方向に探索する初期値 4 | fw = [(1..n*2).to_a] 5 | # 逆方向に探索する初期値 6 | bw = [(1..n*2).to_a.reverse] 7 | 8 | depth = 1 9 | while true do 10 | # 順方向に探索 11 | fw = fw.each_with_object([]) do |c, result| 12 | 1.upto(n){|i| result << c[i, n] + c[0, i] + c[i + n..-1]} 13 | end 14 | break if (fw & bw).size > 0 15 | depth += 1 16 | 17 | # 逆方向に探索 18 | bw = bw.each_with_object([]) do |c, result| 19 | 1.upto(n){|i| result << c[n, i] + c[0, n] + c[i + n..-1]} 20 | end 21 | break if (fw & bw).size > 0 22 | depth += 1 23 | end 24 | 25 | puts depth 26 | -------------------------------------------------------------------------------- /ja_JP/q46_01.rb: -------------------------------------------------------------------------------- 1 | N = 7 2 | checked = {(1..N).to_a => 0} # チェック済みの配列 3 | check = [(1..N).to_a] # チェック対象 4 | depth = 0 # 交換回数 5 | 6 | while check.size > 0 do # チェック対象が存在する間、繰り返す 7 | next_check = [] 8 | (0..(N-1)).to_a.combination(2){|i, j| # 2カ所選択して交換 9 | check.each{|c| 10 | d = c.clone 11 | d[i], d[j] = d[j], d[i] 12 | if !checked.has_key?(d) then 13 | checked[d] = depth + 1 14 | next_check << d 15 | end 16 | } 17 | } 18 | check = next_check 19 | depth += 1 20 | end 21 | 22 | puts checked.values.inject(:+) 23 | -------------------------------------------------------------------------------- /ja_JP/q49_01.rb: -------------------------------------------------------------------------------- 1 | N = 8 # 各色の数 2 | start = (1 << N) - 1 # 開始状態(0がN個、1がN個) 3 | mask = (1 << N * 2) - 1 # ビットマスク 4 | 5 | # ゴール状態(0と1を交互に設定) 6 | goal1 = 0 7 | N.times{|i| goal1 = (goal1 << 2) + 1} 8 | goal2 = mask - goal1 9 | 10 | # 交換回数 11 | count = N * 2 12 | (1 << N*2).times{|i| # 交換する開始位置のビット列 13 | turn = i ^ (i << 1) ^ (i << 2) 14 | turn = (turn ^ (turn >> (N * 2))) & mask 15 | 16 | # ゴールと一致すれば交換する位置の数の最小値を判定 17 | if (start ^ turn == goal1) || (start ^ turn == goal2) then 18 | count = [count, i.to_s(2).count('1')].min 19 | end 20 | } 21 | puts count 22 | -------------------------------------------------------------------------------- /ja_JP/q54_01.rb: -------------------------------------------------------------------------------- 1 | N = 11 2 | cards = [0] * N * 2 # カードの初期値 3 | @count = 0 4 | 5 | def search(cards, num) 6 | if num == N + 1 then # 最後まで置ければ成功 7 | @count += 1 8 | else 9 | # 置けるかどうかをチェックしながら、順に配置 10 | (2 * N - 1 - num).times{|i| 11 | if cards[i] == 0 && cards[i + num + 1] == 0 then 12 | # 置ける場合はカードを配置し、再帰的に探索 13 | cards[i], cards[i + num + 1] = num, num 14 | search(cards, num + 1) 15 | cards[i], cards[i + num + 1] = 0, 0 16 | end 17 | } 18 | end 19 | end 20 | 21 | search(cards, 1) # 最初は「1」のカードを配置 22 | puts @count 23 | -------------------------------------------------------------------------------- /ja_JP/q35_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | @cnt = 0 3 | def search(man_x, man_y, woman_x, woman_y, meet) 4 | if (man_x <= N) && (man_y <= N) && 5 | (woman_x >= 0) && (woman_y >= 0) then 6 | @cnt += 1 if (man_x == N) && (man_y == N) && (meet >= 2) 7 | meet += 1 if (man_x == woman_x) 8 | meet += 1 if (man_y == woman_y) 9 | search(man_x + 1, man_y, woman_x - 1, woman_y, meet) 10 | search(man_x + 1, man_y, woman_x, woman_y - 1, meet) 11 | search(man_x, man_y + 1, woman_x - 1, woman_y, meet) 12 | search(man_x, man_y + 1, woman_x, woman_y - 1, meet) 13 | end 14 | end 15 | 16 | search(0, 0, N, N, 0) 17 | puts @cnt 18 | -------------------------------------------------------------------------------- /zh_CN/q34_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | @cnt = 0 3 | def search(man_x, man_y, woman_x, woman_y, meet) 4 | if (man_x <= N) && (man_y <= N) && 5 | (woman_x >= 0) && (woman_y >= 0) then 6 | @cnt += 1 if (man_x == N) && (man_y == N) && (meet >= 2) 7 | meet += 1 if (man_x == woman_x) 8 | meet += 1 if (man_y == woman_y) 9 | search(man_x + 1, man_y, woman_x - 1, woman_y, meet) 10 | search(man_x + 1, man_y, woman_x, woman_y - 1, meet) 11 | search(man_x, man_y + 1, woman_x - 1, woman_y, meet) 12 | search(man_x, man_y + 1, woman_x, woman_y - 1, meet) 13 | end 14 | end 15 | 16 | search(0, 0, N, N, 0) 17 | puts @cnt 18 | -------------------------------------------------------------------------------- /zh_CN/q37_02.rb: -------------------------------------------------------------------------------- 1 | # 定义表示0〜9数字的比特序列 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 事先得出异或运算结果 6 | flip = Array.new(10) 7 | (0..9).each{|i| 8 | flip[i] = Array.new(10) 9 | (0..9).each{|j| 10 | flip[i][j] = (bit[i]^bit[j]).to_s(2).count("1") 11 | } 12 | } 13 | 14 | # 每次设置翻转比特序列的值为初始值 15 | min = 63 16 | (0..9).to_a.permutation.each{|seq| 17 | sum = 0 18 | (seq.size - 1).times{|j| 19 | # 取得保存好的值 20 | sum += flip[seq[j]][seq[j+1]] 21 | break if min <= sum 22 | } 23 | min = sum if sum < min 24 | } 25 | puts min 26 | -------------------------------------------------------------------------------- /zh_CN/q61_01.rb: -------------------------------------------------------------------------------- 1 | # 设置方格点数目 2 | W, H = 5, 4 3 | # 移动方向 4 | @move = [[0, 1], [0, -1], [1, 0], [-1, 0]] 5 | 6 | @map = Array.new(W * H, false) 7 | 8 | # 递归遍历 9 | def search(x, y, depth) 10 | return 0 if x < 0 || W <= x || y < 0 || H <= y || @map[x + y * W] 11 | return 1 if depth == W * H 12 | cnt = 0 13 | @map[x + y * W] = true 14 | @move.each{|m| # 上下左右移动 15 | cnt += search(x + m[0], y + m[1], depth + 1) 16 | } 17 | @map[x + y * W] = false 18 | return cnt 19 | end 20 | 21 | count = 0 22 | (W * H).times{|i| 23 | count += search(i % W, i / W, 1) 24 | } 25 | # 起点终点互换位置得到的路径和原先一致,所以最终数目减半 26 | puts count / 2 27 | -------------------------------------------------------------------------------- /ja_JP/q09_02.js: -------------------------------------------------------------------------------- 1 | var boy = 20; 2 | var girl = 10; 3 | boy += 1; 4 | girl += 1; 5 | var ary = new Array(girl); 6 | for (var i = 0; i < girl; i++){ 7 | ary[i] = new Array(boy); 8 | for (var j = 0; j < boy; j++){ 9 | ary[i][j] = 0; 10 | } 11 | } 12 | ary[0][0] = 1; 13 | for (var i = 0; i < girl; i++){ 14 | for (var j = 0; j < boy; j++){ 15 | if ((i != j) && (boy - j != girl - i)){ 16 | if (j > 0){ 17 | ary[i][j] += ary[i][j - 1]; 18 | } 19 | if (i > 0){ 20 | ary[i][j] += ary[i - 1][j]; 21 | } 22 | } 23 | } 24 | } 25 | console.log(ary[girl - 2][boy - 1] + ary[girl - 1][boy - 2]); 26 | -------------------------------------------------------------------------------- /ja_JP/q38_02.rb: -------------------------------------------------------------------------------- 1 | # 0〜9を表すビットを定義 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 排他的論理和の結果を先に算出 6 | flip = Array.new(10) 7 | (0..9).each{|i| 8 | flip[i] = Array.new(10) 9 | (0..9).each{|j| 10 | flip[i][j] = (bit[i]^bit[j]).to_s(2).count("1") 11 | } 12 | } 13 | 14 | # 毎回全ビットを反転させた値を初期値とする 15 | min = 63 16 | (0..9).to_a.permutation.each{|seq| 17 | sum = 0 18 | (seq.size - 1).times{|j| 19 | # 保存しておいた値を取得 20 | sum += flip[seq[j]][seq[j+1]] 21 | break if min <= sum 22 | } 23 | min = sum if sum < min 24 | } 25 | puts min 26 | -------------------------------------------------------------------------------- /ja_JP/q62_01.rb: -------------------------------------------------------------------------------- 1 | # 格子点の数を設定 2 | W, H = 5, 4 3 | # 移動する方向 4 | @move = [[0, 1], [0, -1], [1, 0], [-1, 0]] 5 | 6 | @map = Array.new(W * H, false) 7 | 8 | # 再帰的に探索する 9 | def search(x, y, depth) 10 | return 0 if x < 0 || W <= x || y < 0 || H <= y || @map[x + y * W] 11 | return 1 if depth == W * H 12 | cnt = 0 13 | @map[x + y * W] = true 14 | @move.each{|m| # 上下左右に移動 15 | cnt += search(x + m[0], y + m[1], depth + 1) 16 | } 17 | @map[x + y * W] = false 18 | return cnt 19 | end 20 | 21 | count = 0 22 | (W * H).times{|i| 23 | count += search(i % W, i / W, 1) 24 | } 25 | # 始点と終点が逆のパターンは同一とみなすので半分にする 26 | puts count / 2 27 | -------------------------------------------------------------------------------- /ja_JP/q68_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | FREE, USED, WALL = 0, 1, 9 3 | 4 | # 番兵として両端と真ん中に壁をセット 5 | @seat = [WALL] + [FREE] * N + [WALL] + [FREE] * N + [WALL] 6 | 7 | def search(person) 8 | count = 0 9 | # 隣に人がいない座席を探す 10 | @seat.size.times{|i| 11 | if @seat[i] == FREE then 12 | if (@seat[i - 1] != USED) && (@seat[i + 1] != USED) then 13 | # 空いていれば座って、次を探索 14 | @seat[i] = USED 15 | count += search(person + 1) 16 | @seat[i] = FREE 17 | end 18 | end 19 | } 20 | # 隣に人がいない座席があれば上記でカウントした値、その他は階乗 21 | (count > 0) ? count : (1..@seat.count(FREE)).inject(:*) 22 | end 23 | 24 | puts search(0) 25 | -------------------------------------------------------------------------------- /zh_CN/q09_02.js: -------------------------------------------------------------------------------- 1 | var boy = 20; 2 | var girl = 10; 3 | boy += 1; 4 | girl += 1; 5 | var ary = new Array(girl); 6 | for (var i = 0; i < girl; i++){ 7 | ary[i] = new Array(boy); 8 | for (var j = 0; j < boy; j++){ 9 | ary[i][j] = 0; 10 | } 11 | } 12 | ary[0][0] = 1; 13 | for (var i = 0; i < girl; i++){ 14 | for (var j = 0; j < boy; j++){ 15 | if ((i != j) && (boy - j != girl - i)){ 16 | if (j > 0){ 17 | ary[i][j] += ary[i][j - 1]; 18 | } 19 | if (i > 0){ 20 | ary[i][j] += ary[i - 1][j]; 21 | } 22 | } 23 | } 24 | } 25 | console.log(ary[girl - 2][boy - 1] + ary[girl - 1][boy - 2]); 26 | -------------------------------------------------------------------------------- /zh_CN/q67_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | FREE, USED, WALL = 0, 1, 9 3 | 4 | # 在两边和正中间设置墙壁做为边界 5 | @seat = [WALL] + [FREE] * N + [WALL] + [FREE] * N + [WALL] 6 | 7 | def search(person) 8 | count = 0 9 | # 搜索邻座没有人的座位 10 | @seat.size.times{|i| 11 | if @seat[i] == FREE then 12 | if (@seat[i - 1] != USED) && (@seat[i + 1] != USED) then 13 | # 如果有空着的座位,则坐下,接着进入下一轮搜索 14 | @seat[i] = USED 15 | count += search(person + 1) 16 | @seat[i] = FREE 17 | end 18 | end 19 | } 20 | # 存在邻座没有人的座位则采用上述逻辑,剩余的数目用阶乘计算 21 | (count > 0) ? count : (1..@seat.count(FREE)).inject(:*) 22 | end 23 | 24 | puts search(0) 25 | -------------------------------------------------------------------------------- /ja_JP/q48_01.rb: -------------------------------------------------------------------------------- 1 | N = 16 2 | def graycode(value) 3 | # N進数を各桁の配列に分解 4 | digits = [] 5 | while value > 0 6 | digits << value % N 7 | value /= N 8 | end 9 | 10 | # 各桁をグレイコードに変換 11 | (digits.size - 1).times{|i| 12 | digits[i] = (digits[i] - digits[i + 1]) % N 13 | } 14 | # 配列を数値に変換 15 | digits.each_with_index.map{|d, i| d * (N**i)}.inject(:+) 16 | end 17 | 18 | # 最初に戻るまで探索 19 | def search(value) 20 | check = graycode(value) 21 | cnt = 1 22 | while check != value do 23 | check = graycode(check) 24 | cnt += 1 25 | end 26 | cnt 27 | end 28 | 29 | puts search(0x808080) 30 | puts search(0xabcdef) 31 | -------------------------------------------------------------------------------- /zh_CN/q47_01.rb: -------------------------------------------------------------------------------- 1 | N = 16 2 | def graycode(value) 3 | # N進数を各桁の配列に分解 4 | digits = [] 5 | while value > 0 6 | digits << value % N 7 | value /= N 8 | end 9 | 10 | # 各桁をグレイコードに変換 11 | (digits.size - 1).times{|i| 12 | digits[i] = (digits[i] - digits[i + 1]) % N 13 | } 14 | # 配列を数値に変換 15 | digits.each_with_index.map{|d, i| d * (N**i)}.inject(:+) 16 | end 17 | 18 | # 最初に戻るまで探索 19 | def search(value) 20 | check = graycode(value) 21 | cnt = 1 22 | while check != value do 23 | check = graycode(check) 24 | cnt += 1 25 | end 26 | cnt 27 | end 28 | 29 | puts search(0x808080) 30 | puts search(0xabcdef) 31 | -------------------------------------------------------------------------------- /zh_CN/q55_01.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def cut_cake(w, h, diff) 3 | # 如果纵向较长,则替换成横向 4 | w, h = h, w if w < h 5 | # 如果存在缓存,则应用缓存 6 | return @memo[[w, h, diff]] if @memo.has_key?([w, h, diff]) 7 | 8 | # 搜索到最后,除了相差1以外的都设置成无穷大 9 | if w == 1 && h == 1 then 10 | return @memo[[w, h, diff]] = (diff == 1)?0:Float::INFINITY 11 | end 12 | 13 | # 横向纵向切分 14 | tate = (1..(w/2)).map{|i| 15 | h + cut_cake(w - i, h, i * h - diff) 16 | } 17 | yoko = (1..(h/2)).map{|i| 18 | w + cut_cake(w, h - i, w * i - diff) 19 | } 20 | # 从横向纵向两种切法中选较小的一个 21 | @memo[[w, h, diff]] = (tate + yoko).min 22 | end 23 | 24 | puts cut_cake(16, 12, 0) 25 | -------------------------------------------------------------------------------- /ja_JP/q56_01.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def cut_cake(w, h, diff) 3 | # 縦の方が長い場合は横長に置き換える 4 | w, h = h, w if w < h 5 | # メモに存在する場合はメモを使用する 6 | return @memo[[w, h, diff]] if @memo.has_key?([w, h, diff]) 7 | # 最後まで探索した場合、差が1である場合以外は無限大とする 8 | if w == 1 && h == 1 then 9 | return @memo[[w, h, diff]] = (diff == 1)?0:Float::INFINITY 10 | end 11 | 12 | # 縦と横に切ってみる 13 | tate = (1..(w/2)).map{|i| 14 | h + cut_cake(w - i, h, i * h - diff) 15 | } 16 | yoko = (1..(h/2)).map{|i| 17 | w + cut_cake(w, h - i, w * i - diff) 18 | } 19 | # 縦と横の切り方のうち、最小のものを返す 20 | @memo[[w, h, diff]] = (tate + yoko).min 21 | end 22 | 23 | puts cut_cake(16, 12, 0) 24 | -------------------------------------------------------------------------------- /ja_JP/q68_02.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | FREE, USED, WALL = 0, 1, 9 3 | 4 | @memo = {} 5 | 6 | def search(seat) 7 | return @memo[seat] if @memo.has_key?(seat) 8 | count = 0 9 | # 隣に人がいない座席を探す 10 | seat.size.times{|i| 11 | if seat[i] == FREE then 12 | if (seat[i - 1] != USED) && (seat[i + 1] != USED) then 13 | # 空いていれば座って、次を探索 14 | seat[i] = USED 15 | count += search(seat) 16 | seat[i] = FREE 17 | end 18 | end 19 | } 20 | # 隣に人がいない座席があれば上記でカウントした値、その他は階乗 21 | @memo[seat] = (count > 0) ? count : (1..seat.count(FREE)).inject(:*) 22 | end 23 | 24 | puts search([WALL] + [FREE] * N + [WALL] + [FREE] * N + [WALL]) 25 | -------------------------------------------------------------------------------- /zh_CN/q67_02.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | FREE, USED, WALL = 0, 1, 9 3 | 4 | @memo = {} 5 | 6 | def search(seat) 7 | return @memo[seat] if @memo.has_key?(seat) 8 | count = 0 9 | # 搜索邻座没有人的座位 10 | seat.size.times{|i| 11 | if seat[i] == FREE then 12 | if (seat[i - 1] != USED) && (seat[i + 1] != USED) then 13 | # 如果有空着的座位,则坐下,接着进入下一轮搜索 14 | seat[i] = USED 15 | count += search(seat) 16 | seat[i] = FREE 17 | end 18 | end 19 | } 20 | # 存在邻座没有人的座位则采用上述逻辑,剩余的数目用阶乘计算 21 | @memo[seat] = (count > 0) ? count : (1..seat.count(FREE)).inject(:*) 22 | end 23 | 24 | puts search([WALL] + [FREE] * N + [WALL] + [FREE] * N + [WALL]) 25 | -------------------------------------------------------------------------------- /zh_CN/q18_01.rb: -------------------------------------------------------------------------------- 1 | def check(n, pre, log, square) 2 | if n == log.size then 3 | # 全部放置结束 4 | if square.include?(1 + pre) then 5 | # 1和最后一个数之和为平方数时 6 | puts n 7 | p log 8 | return true # 只要找到1种解法就结束 9 | end 10 | else 11 | ((1..n).to_a - log).each{|i| # 遍历没有被使用的数字 12 | if square.include?(pre + i) then 13 | # 如果和前一个数之和为平方数 14 | return true if check(n, i, log + [i], square) 15 | end 16 | } 17 | end 18 | false 19 | end 20 | 21 | n = 2 22 | while true do 23 | # 事先计算平方数(最大值为n的2倍) 24 | square = (2..Math.sqrt(n * 2).floor).map{|i| i ** 2} 25 | break if check(n, 1, [1], square) 26 | n += 1 27 | end 28 | -------------------------------------------------------------------------------- /zh_CN/q52_01.rb: -------------------------------------------------------------------------------- 1 | M, N = 6, 5 # 设置“糖果包装纸”和“糖果本身”的数目 2 | @memo = {} # 内存化所用的哈希表 3 | 4 | def search(candy, color) 5 | return 1 if candy == [0] * N # 所有糖果都包好了 6 | # 如果存在内存化的结果,则使用 7 | return @memo[candy + [color]] if @memo.has_key?(candy + [color]) 8 | 9 | # 统计包装纸和糖果口味不一致的组合 10 | cnt = 0 11 | candy.size.times{|i| 12 | if i != (color % candy.size) then # 不一致的情况 13 | if candy[i] > 0 then # 还剩下糖果的情况 14 | candy[i] -= 1 15 | cnt += search(candy, color + 1) # 进入下一层搜索 16 | candy[i] += 1 17 | end 18 | end 19 | } 20 | @memo[candy + [color]] = cnt # 把糖果的数目和颜色保存起来 21 | end 22 | puts search([M] * N, 0) 23 | -------------------------------------------------------------------------------- /zh_CN/q62-extra-workday.txt: -------------------------------------------------------------------------------- 1 | 2006/01/28 2 | 2006/02/05 3 | 2006/04/29 4 | 2006/04/30 5 | 2006/09/30 6 | 2006/10/08 7 | 2007/02/17 8 | 2007/02/25 9 | 2007/04/28 10 | 2007/04/29 11 | 2007/09/29 12 | 2007/09/30 13 | 2007/12/29 14 | 2008/02/02 15 | 2008/02/03 16 | 2008/05/04 17 | 2008/09/27 18 | 2008/09/28 19 | 2009/01/04 20 | 2009/01/24 21 | 2009/02/01 22 | 2009/05/31 23 | 2009/09/27 24 | 2009/10/10 25 | 2010/02/20 26 | 2010/02/21 27 | 2010/06/12 28 | 2010/06/13 29 | 2010/09/19 30 | 2010/09/25 31 | 2010/09/26 32 | 2010/10/09 33 | 2011/01/30 34 | 2011/02/12 35 | 2011/04/02 36 | 2011/10/08 37 | 2011/10/09 38 | 2011/12/31 39 | 2012/01/21 40 | 2012/01/29 41 | 2012/03/31 42 | 2012/04/01 43 | 2012/04/28 44 | 2012/09/29 45 | -------------------------------------------------------------------------------- /ja_JP/q18_01.rb: -------------------------------------------------------------------------------- 1 | def check(n, pre, log, square) 2 | if n == log.size then 3 | # すべてセットした場合 4 | if square.include?(1 + pre) then 5 | # 1と直前の数の和が平方数の場合 6 | puts n 7 | p log 8 | return true # 1つでも見つかれば終了 9 | end 10 | else 11 | ((1..n).to_a - log).each{|i| # 使用していない数でループ 12 | if square.include?(pre + i) then 13 | # 直前の数との和が平方数の場合 14 | return true if check(n, i, log + [i], square) 15 | end 16 | } 17 | end 18 | false 19 | end 20 | 21 | n = 2 22 | while true do 23 | # 平方数を事前に算出(最大でもnの2倍まで) 24 | square = (2..Math.sqrt(n * 2).floor).map{|i| i ** 2} 25 | break if check(n, 1, [1], square) 26 | n += 1 27 | end 28 | -------------------------------------------------------------------------------- /ja_JP/q53_01.rb: -------------------------------------------------------------------------------- 1 | M, N = 6, 5 # 「お菓子の包み紙」と「中身のお菓子」の数をセット 2 | @memo = {} # メモ化するためのハッシュ 3 | 4 | def search(candy, color) 5 | return 1 if candy == [0] * N # お菓子をすべて包めた 6 | # メモしていたものがあればそれを使う 7 | return @memo[candy + [color]] if @memo.has_key?(candy + [color]) 8 | 9 | # 包み紙と中身が不一致なものをカウント 10 | cnt = 0 11 | candy.size.times{|i| 12 | if i != (color % candy.size) then # 不一致な場合 13 | if candy[i] > 0 then # お菓子が残っている場合 14 | candy[i] -= 1 15 | cnt += search(candy, color + 1) # 次を探索 16 | candy[i] += 1 17 | end 18 | end 19 | } 20 | @memo[candy + [color]] = cnt # お菓子の数と色をメモに保存 21 | end 22 | puts search([M] * N, 0) 23 | -------------------------------------------------------------------------------- /rename.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | function resolve(name) { 5 | return path.resolve(__dirname, `./zh_CN/${name}`) 6 | } 7 | 8 | let files = fs.readdirSync(resolve('')); 9 | 10 | files.forEach(filename => { 11 | const match = /q(\d+)/.exec(filename) 12 | if (match) { 13 | const num = parseInt(match[1]) 14 | if (num > 33) { 15 | const targetName = filename.replace(/q\d+/, `q${num - 1}`) 16 | fs.rename(resolve(filename), resolve(targetName), err => { 17 | if (!err) { 18 | console.log(filename + ' => ' + targetName) 19 | } 20 | }) 21 | } 22 | } 23 | }) 24 | 25 | -------------------------------------------------------------------------------- /ja_JP/q52_01.rb: -------------------------------------------------------------------------------- 1 | N = 8 # 砂時計の数 2 | GOAL = [1] * N # すべて1になれば次に同時に下に落ちる 3 | 4 | count = 0 5 | (1..N).to_a.permutation{|init| # 初期状態を順列で設定 6 | hourglass = init 7 | pos = 0 8 | log = {} # 同じ状態になるかをチェックするログ 9 | while log[hourglass] != pos # 過去に同じ状態があれば終了 10 | if hourglass == GOAL then # 目標の形に達したら終了 11 | count += 1 12 | break 13 | end 14 | log[hourglass] = pos 15 | 16 | # 砂時計を減らす(残っていない場合はそのまま) 17 | hourglass = hourglass.map{|h| h > 0 ? h - 1 : 0} 18 | init[pos].times{|i| # 砂時計を反転 19 | rev = (pos + i) % N 20 | hourglass[rev] = init[rev] - hourglass[rev] 21 | } 22 | pos = (pos + 1) % N # 次の位置に移動 23 | end 24 | } 25 | 26 | puts count 27 | -------------------------------------------------------------------------------- /ja_JP/q40_02.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | if cards[0] == 1 then 7 | if @max < depth 8 | @max = depth 9 | @max_list.clear 10 | end 11 | @max_list[init] = cards if @max == depth 12 | else 13 | solve(cards[0..(cards[0] - 1)].reverse + cards[cards[0]..N], 14 | init, depth + 1) 15 | end 16 | end 17 | 18 | def pattern(used, unused, index) 19 | if unused.empty? 20 | solve(used, used, 0) 21 | else 22 | unused.select{|i| index + 1 != i}.each{|i| 23 | pattern(used + [i], unused - [i], index + 1) 24 | } 25 | end 26 | end 27 | 28 | pattern([], (1..N).to_a, 0) 29 | puts @max 30 | puts @max_list 31 | -------------------------------------------------------------------------------- /zh_CN/q39_02.rb: -------------------------------------------------------------------------------- 1 | N = 9 2 | @max = 0 3 | @max_list = Hash.new 4 | 5 | def solve(cards, init, depth) 6 | if cards[0] == 1 then 7 | if @max < depth 8 | @max = depth 9 | @max_list.clear 10 | end 11 | @max_list[init] = cards if @max == depth 12 | else 13 | solve(cards[0..(cards[0] - 1)].reverse + cards[cards[0]..N], 14 | init, depth + 1) 15 | end 16 | end 17 | 18 | def pattern(used, unused, index) 19 | if unused.empty? 20 | solve(used, used, 0) 21 | else 22 | unused.select{|i| index + 1 != i}.each{|i| 23 | pattern(used + [i], unused - [i], index + 1) 24 | } 25 | end 26 | end 27 | 28 | pattern([], (1..N).to_a, 0) 29 | puts @max 30 | puts @max_list 31 | -------------------------------------------------------------------------------- /zh_CN/q51_01.rb: -------------------------------------------------------------------------------- 1 | N = 8 # 沙漏数目 2 | GOAL = [1] * N # 如果所有沙漏剩余砂量为1,则所有砂子能同时落下 3 | 4 | count = 0 5 | (1..N).to_a.permutation{|init| # 顺次设置初始状态 6 | hourglass = init 7 | pos = 0 8 | log = {} # 用于检查是否变为同样状态的记录 9 | while log[hourglass] != pos # 如果变为过去的同样状态,则终止处理 10 | if hourglass == GOAL then # 如果变为目标状态,则处理结束 11 | count += 1 12 | break 13 | end 14 | log[hourglass] = pos 15 | 16 | # 减少沙漏砂量(如果上侧砂量为0,则保持为0) 17 | hourglass = hourglass.map{|h| h > 0 ? h - 1 : 0} 18 | init[pos].times{|i| # 反转沙漏 19 | rev = (pos + i) % N 20 | hourglass[rev] = init[rev] - hourglass[rev] 21 | } 22 | pos = (pos + 1) % N # 移动到下一个位置 23 | end 24 | } 25 | 26 | puts count 27 | -------------------------------------------------------------------------------- /zh_CN/q25_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | 3 | max_cnt = 0 4 | (1..N - 1).to_a.permutation(N - 1){|l| # 左侧的顺序 5 | (1..N - 1).to_a.permutation(N - 1){|r| # 右侧的顺序 6 | # 设置连线 7 | path = [] 8 | left = 0 9 | right = r[0] 10 | (N - 1).times{|i| 11 | path.push([left, right]) 12 | left = l[i] 13 | path.push([left, right]) 14 | right = r[i + 1] 15 | } 16 | path.push([left, 0]) 17 | 18 | # 判断连线是否相交 19 | cnt = 0 20 | (N * 2 - 1).times{|i| 21 | (i + 1).upto(N * 2 - 2){|j| 22 | cnt += 1 if (path[i][0] - path[j][0]) * 23 | (path[i][1] - path[j][1]) < 0 24 | } 25 | } 26 | max_cnt = [max_cnt, cnt].max 27 | } 28 | } 29 | puts max_cnt 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《程序员的算法趣题》随书源码等 2 | 3 | 《程序员的算法趣题》随书源码等在线内容 4 | 5 | ## 书籍信息 6 | 7 | ### 原书 8 | 9 | 项目 | 内容 10 | ---- | ---- 11 | 书名 | [《プログラマ脳を鍛える数学パズル》](http://www.shoeisha.co.jp/book/detail/9784798142456) 12 | ISBN | 978-479814245 13 | 出版日期 | 2015-10-13 14 | 作者 | [増井 敏克](http://masuipeo.com/index.html) 15 | 发行地区 | 日本 16 | 出版社 | [翔泳社](http://www.shoeisha.co.jp/) 17 | 版式 | A5 x 312页 18 | 19 | ### 译本 20 | 21 | 项目 | 内容 22 | ---- | ---- 23 | 书名 | [《程序员的算法趣题》](http://www.ituring.com.cn/book/1814) 24 | ISBN | 978-7-115-45923-7 25 | 出版日期 | 2017-07-25 26 | 译者 | [绝云](http://blog.leungwensen.com/) 27 | 发行地区 | 中国大陆 28 | 出版社 | [北京图灵文化发展有限公司](http://www.ituring.com.cn/) 29 | 版式 | A5 x 312页 30 | 31 | ## 源码 32 | 33 | - [简体中文注释版](./zh_CN) 34 | - [日文注释版](./ja_JP) 35 | -------------------------------------------------------------------------------- /ja_JP/q25_01.rb: -------------------------------------------------------------------------------- 1 | N = 6 2 | 3 | max_cnt = 0 4 | (1..N - 1).to_a.permutation(N - 1){|l| # 左側の順番 5 | (1..N - 1).to_a.permutation(N - 1){|r| # 右側の順番 6 | # 経路を設定 7 | path = [] 8 | left = 0 9 | right = r[0] 10 | (N - 1).times{|i| 11 | path.push([left, right]) 12 | left = l[i] 13 | path.push([left, right]) 14 | right = r[i + 1] 15 | } 16 | path.push([left, 0]) 17 | 18 | # 経路が交差しているかを判定 19 | cnt = 0 20 | (N * 2 - 1).times{|i| 21 | (i + 1).upto(N * 2 - 2){|j| 22 | cnt += 1 if (path[i][0] - path[j][0]) * 23 | (path[i][1] - path[j][1]) < 0 24 | } 25 | } 26 | max_cnt = [max_cnt, cnt].max 27 | } 28 | } 29 | puts max_cnt 30 | -------------------------------------------------------------------------------- /zh_CN/q55_02.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def cut_cake(w, h, diff) 3 | # 如果纵向较长,则替换成横向 4 | w, h = h, w if w < h 5 | # 如果存在缓存,则应用缓存 6 | return @memo[[w, h, diff]] if @memo.has_key?([w, h, diff]) 7 | 8 | # 搜索到最后,除了相差1以外的都设置成无穷大 9 | if w == 1 && h == 1 then 10 | return @memo[[w, h, diff]] = (diff == 1)?0:Float::INFINITY 11 | end 12 | 13 | # 剪枝(相差大于蛋糕的一半,则设置为无穷大) 14 | return Float::INFINITY if w * h / 2 < diff 15 | 16 | # 横向纵向切分 17 | tate = (1..(w/2)).map{|i| 18 | h + cut_cake(w - i, h, i * h - diff) 19 | } 20 | yoko = (1..(h/2)).map{|i| 21 | w + cut_cake(w, h - i, w * i - diff) 22 | } 23 | # 从横向纵向两种切法中选较小的一个 24 | @memo[[w, h, diff]] = (tate + yoko).min 25 | end 26 | 27 | puts cut_cake(16, 12, 0) 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | ## Specific to RubyMotion: 14 | .dat* 15 | .repl_history 16 | build/ 17 | 18 | ## Documentation cache and generated files: 19 | /.yardoc/ 20 | /_yardoc/ 21 | /doc/ 22 | /rdoc/ 23 | 24 | ## Environment normalization: 25 | /.bundle/ 26 | /vendor/bundle 27 | /lib/bundler/man/ 28 | 29 | # for a library or gem, you might want to ignore these files since the code is 30 | # intended to run in multiple environments; otherwise, check them in: 31 | # Gemfile.lock 32 | # .ruby-version 33 | # .ruby-gemset 34 | 35 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 36 | .rvmrc 37 | -------------------------------------------------------------------------------- /zh_CN/q69_01.rb: -------------------------------------------------------------------------------- 1 | # 把终止状态设置为初始值 2 | memo = {0x000fff => 0, 0xfff000 => 0, 0xcccccc => 0, 0x333333 => 0} 3 | queue = memo.keys 4 | W, H = 4, 6 5 | 6 | # 指定可能交换的位置 7 | mask = [] 8 | (W * H).times{|i| 9 | mask.push((1 << 1 | 1) << i) if i % W < W - 1 # 横向相邻 10 | mask.push((1 << W | 1) << i) if i < W * (H - 1) # 纵向相邻 11 | } 12 | 13 | depth = 0 14 | while queue.size > 0 do # 遍历所有情况 15 | p [depth, queue.size] 16 | depth += 1 17 | next_queue = [] 18 | queue.map{|q| 19 | mask.each{|m| 20 | # 除去2个位置“都是0”或者“都是1”的情况以外,遍历未搜索的部分 21 | if ((q & m) != 0) && ((q & m) != m) && !memo.key?(q ^ m) then 22 | memo[q ^ m] = depth 23 | next_queue.push(q ^ m) 24 | end 25 | } 26 | } 27 | queue = next_queue 28 | end 29 | -------------------------------------------------------------------------------- /zh_CN/q36_03.rb: -------------------------------------------------------------------------------- 1 | # 获取下一个数字序列 2 | def next_dice(dice) 3 | top = dice.div(6**5) 4 | left, right = dice.divmod(6**(5 - top)) 5 | (right + 1) * (6**(top + 1)) - (left + 1) 6 | end 7 | 8 | # 记录已检索的值(0:未检索,1:循环外,2:循环内) 9 | all_dice = Array.new(6 ** 6, 0) 10 | (6**6).times{|i| 11 | if all_dice[i] == 0 then 12 | check = Array.new 13 | while (all_dice[i] == 0) && (!check.include?(i)) do 14 | check << i 15 | i = next_dice(i) 16 | end 17 | index = check.index(i) 18 | if (index) then # 循环发生点,这个位置前是循环外 19 | check.shift(index).each{|j| all_dice[j] = 1} 20 | check.each{|j| all_dice[j] = 2} 21 | else # 包含已检索值时为循环外 22 | check.each{|j| all_dice[j] = 1} 23 | end 24 | end 25 | } 26 | puts all_dice.count(1) 27 | -------------------------------------------------------------------------------- /ja_JP/q10_02.rb: -------------------------------------------------------------------------------- 1 | european = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 2 | 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 3 | 22, 18, 29, 7, 28, 12, 35, 3, 26] 4 | american = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 5 | 3, 24, 36, 13, 1, 00, 27, 10, 25, 29, 12, 8, 19, 31, 6 | 18, 6, 21, 33, 16, 4, 23, 35, 14, 2] 7 | 8 | def sum_max(roulette, n) 9 | ans = roulette[0, n].inject(:+) 10 | tmp = ans 11 | roulette.size.times{|i| 12 | tmp += roulette[(i + n) % roulette.size] 13 | tmp -= roulette[i] 14 | ans = [ans, tmp].max 15 | } 16 | ans 17 | end 18 | 19 | cnt = 0 20 | (2..36).each{|i| 21 | cnt += 1 if sum_max(european, i) < sum_max(american, i) 22 | } 23 | puts cnt 24 | -------------------------------------------------------------------------------- /ja_JP/q55_01.rb: -------------------------------------------------------------------------------- 1 | # 元の数に加算した場合に移動する量を返す 2 | def move(base, add) 3 | # 10の位の5の玉の位置を確認 4 | a0, a1 = (base + add).divmod(50) 5 | b0, b1 = base.divmod(50) 6 | 7 | # 10の位の1の玉の位置を確認 8 | a2, a3 = a1.divmod(10) 9 | b2, b3 = b1.divmod(10) 10 | 11 | # 1の位の玉の位置を確認 12 | a4, a5 = a3.divmod(5) 13 | b4, b5 = b3.divmod(5) 14 | 15 | # すべての位置の差から動かす量を加算 16 | (a0 - b0).abs + (a2 - b2).abs + (a4 - b4).abs + (a5 - b5).abs 17 | end 18 | 19 | # 移動するリストに対して、移動量を合計 20 | def count(list) 21 | cnt = total = 0 22 | list.each{|i| 23 | cnt += move(total, i) 24 | total += i 25 | } 26 | cnt 27 | end 28 | 29 | # 1〜10までの順列について最少の移動量を求める 30 | min = 100 31 | (1..10).to_a.permutation(10){|s| 32 | min = [min, count(s)].min 33 | } 34 | puts min 35 | -------------------------------------------------------------------------------- /ja_JP/q56_02.rb: -------------------------------------------------------------------------------- 1 | @memo = {} 2 | def cut_cake(w, h, diff) 3 | # 縦の方が長い場合は横長に置き換える 4 | w, h = h, w if w < h 5 | # メモに存在する場合はメモを使用する 6 | return @memo[[w, h, diff]] if @memo.has_key?([w, h, diff]) 7 | 8 | # 最後まで探索した場合、差が1である場合以外は無限大とする 9 | if w == 1 && h == 1 then 10 | return @memo[[w, h, diff]] = (diff == 1)?0:Float::INFINITY 11 | end 12 | 13 | # 枝刈り(差がケーキの半分を超えると無限大とする) 14 | return Float::INFINITY if w * h / 2 < diff 15 | 16 | # 縦と横に切ってみる 17 | tate = (1..(w/2)).map{|i| 18 | h + cut_cake(w - i, h, i * h - diff) 19 | } 20 | yoko = (1..(h/2)).map{|i| 21 | w + cut_cake(w, h - i, w * i - diff) 22 | } 23 | # 縦と横の切り方のうち、最小のものを返す 24 | @memo[[w, h, diff]] = (tate + yoko).min 25 | end 26 | 27 | puts cut_cake(16, 12, 0) 28 | -------------------------------------------------------------------------------- /zh_CN/q10_02.rb: -------------------------------------------------------------------------------- 1 | european = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 2 | 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 3 | 22, 18, 29, 7, 28, 12, 35, 3, 26] 4 | american = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 5 | 3, 24, 36, 13, 1, 00, 27, 10, 25, 29, 12, 8, 19, 31, 6 | 18, 6, 21, 33, 16, 4, 23, 35, 14, 2] 7 | 8 | def sum_max(roulette, n) 9 | ans = roulette[0, n].inject(:+) 10 | tmp = ans 11 | roulette.size.times{|i| 12 | tmp += roulette[(i + n) % roulette.size] 13 | tmp -= roulette[i] 14 | ans = [ans, tmp].max 15 | } 16 | ans 17 | end 18 | 19 | cnt = 0 20 | (2..36).each{|i| 21 | cnt += 1 if sum_max(european, i) < sum_max(american, i) 22 | } 23 | puts cnt 24 | -------------------------------------------------------------------------------- /ja_JP/q70_01.rb: -------------------------------------------------------------------------------- 1 | # ゴールを初期値として設定 2 | memo = {0x000fff => 0, 0xfff000 => 0, 0xcccccc => 0, 0x333333 => 0} 3 | queue = memo.keys 4 | W, H = 4, 6 5 | 6 | # 交換可能な位置を設定 7 | mask = [] 8 | (W * H).times{|i| 9 | mask.push((1 << 1 | 1) << i) if i % W < W - 1 # 横に隣り合う 10 | mask.push((1 << W | 1) << i) if i < W * (H - 1) # 縦に隣り合う 11 | } 12 | 13 | depth = 0 14 | while queue.size > 0 do # 探索すべきものがある限り繰り返す 15 | p [depth, queue.size] 16 | depth += 1 17 | next_queue = [] 18 | queue.map{|q| 19 | mask.each{|m| 20 | # 2カ所が「両方0」か「両方1」の場合以外で未探索の部分を探索 21 | if ((q & m) != 0) && ((q & m) != m) && !memo.key?(q ^ m) then 22 | memo[q ^ m] = depth 23 | next_queue.push(q ^ m) 24 | end 25 | } 26 | } 27 | queue = next_queue 28 | end 29 | -------------------------------------------------------------------------------- /zh_CN/q69_03.rb: -------------------------------------------------------------------------------- 1 | memo = {0x000fff => 0, 0xfff000 => 0, 0xcccccc => 0, 0x333333 => 0} 2 | queue = [0x000fff, 0x333333] # 只保留左上为0的初始值 3 | W, H = 4, 6 4 | 5 | mask = [] 6 | (W * H).times{|i| 7 | mask.push((1 << 1 | 1) << i) if i % W < W - 1 8 | mask.push((1 << W | 1) << i) if i < W * (H - 1) 9 | } 10 | 11 | depth = 0 12 | while queue.size > 0 do 13 | p [depth, queue.size * 2] # 答案乘以2 14 | depth += 1 15 | next_queue = [] 16 | queue.map{|q| 17 | mask.each{|m| 18 | if ((q & m) != 0) && ((q & m) != m) && !memo.key?(q ^ m) then 19 | memo[q ^ m] = depth 20 | # 缓存按位取反的结果 21 | memo[(q ^ m) ^ ((1 << W * H) - 1)] = depth 22 | next_queue.push(q ^ m) 23 | end 24 | } 25 | } 26 | queue = next_queue 27 | end 28 | -------------------------------------------------------------------------------- /ja_JP/q37_03.rb: -------------------------------------------------------------------------------- 1 | # 次の目を取得する 2 | def next_dice(dice) 3 | top = dice.div(6**5) 4 | left, right = dice.divmod(6**(5 - top)) 5 | (right + 1) * (6**(top + 1)) - (left + 1) 6 | end 7 | 8 | # 探索した値を記録する(0:未探索、1:ループ以外、2:ループ) 9 | all_dice = Array.new(6 ** 6, 0) 10 | (6**6).times{|i| 11 | if all_dice[i] == 0 then 12 | check = Array.new 13 | while (all_dice[i] == 0) && (!check.include?(i)) do 14 | check << i 15 | i = next_dice(i) 16 | end 17 | index = check.index(i) 18 | if (index) then # ループしたとき、その位置以前はループ以外 19 | check.shift(index).each{|j| all_dice[j] = 1} 20 | check.each{|j| all_dice[j] = 2} 21 | else # すでにチェック済みの値に当たった時はループ以外 22 | check.each{|j| all_dice[j] = 1} 23 | end 24 | end 25 | } 26 | puts all_dice.count(1) 27 | -------------------------------------------------------------------------------- /ja_JP/q62_03.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define W 5 4 | #define H 4 5 | 6 | int map = 0; 7 | 8 | int search(int x, int y, int depth){ 9 | int cnt = 0; 10 | if ((x < 0) || (W <= x) || (y < 0) || (H <= y)) return 0; 11 | if ((map & (1 << (x + y * W))) > 0) return 0; 12 | if (depth == W * H) return 1; 13 | map += 1 << (x + y * W); 14 | cnt += search(x + 1, y, depth + 1); 15 | cnt += search(x - 1, y, depth + 1); 16 | cnt += search(x, y + 1, depth + 1); 17 | cnt += search(x, y - 1, depth + 1); 18 | map -= 1 << (x + y * W); 19 | return cnt; 20 | } 21 | 22 | int main(void) { 23 | int count = 0; 24 | int i; 25 | for (i = 0; i < W * H; i++){ 26 | count += search(i % W, i / W, 1); 27 | } 28 | printf("%d", count / 2); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /ja_JP/q70_03.rb: -------------------------------------------------------------------------------- 1 | memo = {0x000fff => 0, 0xfff000 => 0, 0xcccccc => 0, 0x333333 => 0} 2 | queue = [0x000fff, 0x333333] # 初期値を左上が0のもののみに絞る 3 | W, H = 4, 6 4 | 5 | mask = [] 6 | (W * H).times{|i| 7 | mask.push((1 << 1 | 1) << i) if i % W < W - 1 8 | mask.push((1 << W | 1) << i) if i < W * (H - 1) 9 | } 10 | 11 | depth = 0 12 | while queue.size > 0 do 13 | p [depth, queue.size * 2] # 答えは2倍する 14 | depth += 1 15 | next_queue = [] 16 | queue.map{|q| 17 | mask.each{|m| 18 | if ((q & m) != 0) && ((q & m) != m) && !memo.key?(q ^ m) then 19 | memo[q ^ m] = depth 20 | # ビットを反転したものをメモにセットする 21 | memo[(q ^ m) ^ ((1 << W * H) - 1)] = depth 22 | next_queue.push(q ^ m) 23 | end 24 | } 25 | } 26 | queue = next_queue 27 | end 28 | -------------------------------------------------------------------------------- /zh_CN/q61_03.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define W 5 4 | #define H 4 5 | 6 | int map = 0; 7 | 8 | int search(int x, int y, int depth){ 9 | int cnt = 0; 10 | if ((x < 0) || (W <= x) || (y < 0) || (H <= y)) return 0; 11 | if ((map & (1 << (x + y * W))) > 0) return 0; 12 | if (depth == W * H) return 1; 13 | map += 1 << (x + y * W); 14 | cnt += search(x + 1, y, depth + 1); 15 | cnt += search(x - 1, y, depth + 1); 16 | cnt += search(x, y + 1, depth + 1); 17 | cnt += search(x, y - 1, depth + 1); 18 | map -= 1 << (x + y * W); 19 | return cnt; 20 | } 21 | 22 | int main(void) { 23 | int count = 0; 24 | int i; 25 | for (i = 0; i < W * H; i++){ 26 | count += search(i % W, i / W, 1); 27 | } 28 | printf("%d", count / 2); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /zh_CN/q44_01.rb: -------------------------------------------------------------------------------- 1 | require "prime" 2 | 3 | # 获取3位的质数 4 | primes = Prime.each(1000).select{|i| i >= 100} 5 | 6 | # 以首位数字生成哈希表 7 | prime_h = {0 => []} 8 | primes.chunk{|i| i / 100}.each{|k, v| 9 | prime_h[k] = v 10 | } 11 | 12 | cnt = 0 13 | primes.each{|r1| # 第1行 14 | prime_h[r1 / 100].each{|c1| # 第1列 15 | prime_h[r1 % 100 / 10].each{|c2| # 第2列 16 | prime_h[r1 % 10].each{|c3| # 第3列 17 | r2 = (c1 % 100 / 10) * 100 + (c2 % 100 / 10) * 10 + 18 | (c3 % 100 / 10) 19 | r3 = (c1 % 10) * 100 + (c2 % 10) * 10 + (c3 % 10) 20 | if primes.include?(r2) && primes.include?(r3) then 21 | cnt += 1 if [r1, r2, r3, c1, c2, c3].uniq.size == 6 22 | end 23 | } 24 | } 25 | } 26 | } 27 | puts cnt 28 | -------------------------------------------------------------------------------- /ja_JP/q45_01.rb: -------------------------------------------------------------------------------- 1 | require "prime" 2 | 3 | # 3桁の素数を取得 4 | primes = Prime.each(1000).select{|i| i >= 100} 5 | 6 | # 先頭の桁でハッシュを作成 7 | prime_h = {0 => []} 8 | primes.chunk{|i| i / 100}.each{|k, v| 9 | prime_h[k] = v 10 | } 11 | 12 | cnt = 0 13 | primes.each{|r1| # 1行目 14 | prime_h[r1 / 100].each{|c1| # 1列目 15 | prime_h[r1 % 100 / 10].each{|c2| # 2列目 16 | prime_h[r1 % 10].each{|c3| # 3列目 17 | r2 = (c1 % 100 / 10) * 100 + (c2 % 100 / 10) * 10 + 18 | (c3 % 100 / 10) 19 | r3 = (c1 % 10) * 100 + (c2 % 10) * 10 + (c3 % 10) 20 | if primes.include?(r2) && primes.include?(r3) then 21 | cnt += 1 if [r1, r2, r3, c1, c2, c3].uniq.size == 6 22 | end 23 | } 24 | } 25 | } 26 | } 27 | puts cnt 28 | -------------------------------------------------------------------------------- /ja_JP/q44_01.rb: -------------------------------------------------------------------------------- 1 | def search(abc, depth, max_abc, log) 2 | return false if log.has_key?(abc) # 探索済み 3 | return true if abc[0] == max_abc[0] / 2 # 終了条件 4 | log[abc] = depth 5 | [0, 1, 2].permutation(2).each{|i, j| 6 | # A, B, Cのうち移動する2つを選択 7 | if (abc[i] > 0) || (abc[j] < max_abc[j]) 8 | next_abc = abc.clone 9 | move = [abc[i], max_abc[j] - abc[j]].min 10 | next_abc[i] -= move 11 | next_abc[j] += move 12 | return true if search(next_abc, depth + 1, max_abc, log) 13 | end 14 | } 15 | false 16 | end 17 | 18 | cnt = 0 19 | 10.step(100, 2){|a| 20 | (1..(a/2 - 1)).each{|c| 21 | b = a - c 22 | if b.gcd(c) == 1 then # 互いに素の場合は最大公約数=1 23 | cnt += 1 if search([a, 0, 0], 0, [a, b, c], {}) 24 | end 25 | } 26 | } 27 | puts cnt 28 | -------------------------------------------------------------------------------- /zh_CN/q38_01.rb: -------------------------------------------------------------------------------- 1 | # 设置反转用的掩码 2 | mask = Array.new(16) 3 | 4.times{|row| 4 | 4.times{|col| 5 | mask[row * 4 + col] = 6 | (0b1111 << (row * 4)) | (0b1000100010001 << col) 7 | } 8 | } 9 | 10 | max = 0 11 | # 保存步骤数目的数组 12 | steps = Array.new(1 << 16, -1) 13 | # 从所有方格都为白色开始 14 | steps[0] = 0 15 | # 检查对象的数组 16 | scanner = [0] 17 | while scanner.size > 0 do 18 | check = scanner.shift 19 | next_steps = steps[check] + 1 20 | 16.times{|i| 21 | n = check ^ mask[i] 22 | # 如果未检查过,则进一步检索 23 | if steps[n] == -1 then 24 | steps[n] = next_steps 25 | scanner.push(n) 26 | max = next_steps if max < next_steps 27 | end 28 | } 29 | end 30 | 31 | puts max # 最大步骤数 32 | puts steps.index(max).to_s(2) # 初始状态的方格:全部黑色 33 | p steps.select{|i| i == -1} # 不存在不能全部变为白色的初始状态 34 | -------------------------------------------------------------------------------- /zh_CN/q55_03.js: -------------------------------------------------------------------------------- 1 | var memo = {}; 2 | function cut_cake(w, h, diff){ 3 | if (w < h){ 4 | var temp = w; w = h; h = temp; 5 | } 6 | if ([w, h, diff] in memo){ 7 | return memo[[w, h, diff]]; 8 | } 9 | if ((w == 1) && (h == 1)){ 10 | return memo[[w, h, diff]] = (diff == 1)?0:Infinity; 11 | } 12 | if (w * h < diff * 2){ 13 | return Infinity; 14 | } 15 | 16 | /* 横向纵向切分 */ 17 | var result = new Array(); 18 | for (var i = 1; i <= parseInt(w / 2); i++){ 19 | result.push(h + cut_cake(w - i, h, i * h - diff)); 20 | } 21 | for (var i = 1; i <= parseInt(h / 2); i++){ 22 | result.push(w + cut_cake(w, h - i, w * i - diff)); 23 | } 24 | /* 从横向纵向两种切法中选较小的一个 */ 25 | return memo[[w, h, diff]] = Math.min.apply(null, result); 26 | } 27 | console.log(cut_cake(16, 12, 0)); 28 | -------------------------------------------------------------------------------- /ja_JP/q39_01.rb: -------------------------------------------------------------------------------- 1 | # 反転するマスクを設定 2 | mask = Array.new(16) 3 | 4.times{|row| 4 | 4.times{|col| 5 | mask[row * 4 + col] = 6 | (0b1111 << (row * 4)) | (0b1000100010001 << col) 7 | } 8 | } 9 | 10 | max = 0 11 | # ステップ数を保存する配列 12 | steps = Array.new(1 << 16, -1) 13 | # すべて白からスタート 14 | steps[0] = 0 15 | # 調査対象の配列 16 | scanner = [0] 17 | while scanner.size > 0 do 18 | check = scanner.shift 19 | next_steps = steps[check] + 1 20 | 16.times{|i| 21 | n = check ^ mask[i] 22 | # 未チェックの場合、さらに調査する 23 | if steps[n] == -1 then 24 | steps[n] = next_steps 25 | scanner.push(n) 26 | max = next_steps if max < next_steps 27 | end 28 | } 29 | end 30 | 31 | puts max # 最大ステップ数 32 | puts steps.index(max).to_s(2) # 初期状態のマス目:すべて黒 33 | p steps.select{|i| i == -1} # 白にならない初期状態は無い 34 | -------------------------------------------------------------------------------- /ja_JP/q56_03.js: -------------------------------------------------------------------------------- 1 | var memo = {}; 2 | function cut_cake(w, h, diff){ 3 | if (w < h){ 4 | var temp = w; w = h; h = temp; 5 | } 6 | if ([w, h, diff] in memo){ 7 | return memo[[w, h, diff]]; 8 | } 9 | if ((w == 1) && (h == 1)){ 10 | return memo[[w, h, diff]] = (diff == 1)?0:Infinity; 11 | } 12 | if (w * h < diff * 2){ 13 | return Infinity; 14 | } 15 | 16 | /* 縦と横に切ってみる */ 17 | var result = new Array(); 18 | for (var i = 1; i <= parseInt(w / 2); i++){ 19 | result.push(h + cut_cake(w - i, h, i * h - diff)); 20 | } 21 | for (var i = 1; i <= parseInt(h / 2); i++){ 22 | result.push(w + cut_cake(w, h - i, w * i - diff)); 23 | } 24 | /* 縦と横の切り方のうち、最小のものを返す */ 25 | return memo[[w, h, diff]] = Math.min.apply(null, result); 26 | } 27 | console.log(cut_cake(16, 12, 0)); 28 | -------------------------------------------------------------------------------- /zh_CN/q65_01.rb: -------------------------------------------------------------------------------- 1 | # 设置图块数目 2 | W, H = 4, 3 3 | # 按位反转用的值 4 | XOR_ROW = (1 << (W + 1)) - 1 5 | 6 | # 按行搜索 7 | def search(up, y, odds) 8 | # 截至上一行,如果奇数顶点的数目大于2,则排除这种情况 9 | return 0 if 2 < odds 10 | 11 | row = 1 << W | 1 # 设置初始值 12 | 13 | # 翻转最初和最后的行 14 | row = XOR_ROW ^ row if (y == 0) || (y == H) 15 | 16 | if y == H then # 如果是最后一行,则检查后结束 17 | odds += (row ^ up).to_s(2).count("1") # 计算奇数个数 18 | return 1 if (odds == 0) || (odds == 2) # 如果为0或者2,则计入结果 19 | return 0 20 | end 21 | cnt = 0 22 | (1 << W).times{|a| # 图块内容(有无左上至右下的线条) 23 | (1 << W).times{|b| # 图块内容(有无左下至右上的线条) 24 | cnt += search(a ^ b << 1, y + 1, 25 | odds + (row ^ up ^ a << 1 ^ b).to_s(2).count("1")) 26 | } 27 | } 28 | return cnt 29 | end 30 | 31 | puts search(0, 0, 0) 32 | -------------------------------------------------------------------------------- /ja_JP/q66_01.rb: -------------------------------------------------------------------------------- 1 | # パネルの数を設定 2 | W, H = 4, 3 3 | # ビット反転用の値 4 | XOR_ROW = (1 << (W + 1)) - 1 5 | 6 | # 行単位に探索 7 | def search(up, y, odds) 8 | # 上の行までに奇数の数が2つより多い場合は対象外 9 | return 0 if 2 < odds 10 | 11 | row = 1 << W | 1 # 初期値をセット 12 | 13 | # 最初と最後の行は反転 14 | row = XOR_ROW ^ row if (y == 0) || (y == H) 15 | 16 | if y == H then # 最終行の場合はチェックして終了 17 | odds += (row ^ up).to_s(2).count("1") # 奇数の数をカウント 18 | return 1 if (odds == 0) || (odds == 2) # 0か2個なら対象 19 | return 0 20 | end 21 | cnt = 0 22 | (1 << W).times{|a| # パネルの内容(左上から右下の直線有無) 23 | (1 << W).times{|b| # パネルの内容(左下から右上の直線有無) 24 | cnt += search(a ^ b << 1, y + 1, 25 | odds + (row ^ up ^ a << 1 ^ b).to_s(2).count("1")) 26 | } 27 | } 28 | return cnt 29 | end 30 | 31 | puts search(0, 0, 0) 32 | -------------------------------------------------------------------------------- /ja_JP/q18_02.rb: -------------------------------------------------------------------------------- 1 | def check(last_n, used, list) 2 | # すべて使用済みで、先頭の「1」と平方数になると終了 3 | return [1] if used.all? && (list[1].include?(last_n)) 4 | list[last_n].each{|i| # 候補を順に試す 5 | if used[i - 1] == false then # 使用済みでない場合 6 | used[i - 1] = true 7 | result = check(i, used, list) 8 | # 見つけた場合は、その値を追加して返す 9 | return [i] + result if result.size > 0 10 | used[i - 1] = false 11 | end 12 | } 13 | [] 14 | end 15 | 16 | n = 2 17 | while true do 18 | square = (2..Math.sqrt(n * 2).floor).map{|i| i ** 2} 19 | # 隣り合う可能性がある候補を作成 20 | list = {} 21 | (1..n).each{|i| 22 | list[i] = square.map{|s| s - i}.select{|s| s > 0} 23 | } 24 | # 「1」を使用済みにして、「1」から探索開始 25 | result = check(1, [true] + [false] * (n - 1), list) 26 | break if result.size > 0 27 | n += 1 28 | end 29 | puts n 30 | p result 31 | -------------------------------------------------------------------------------- /zh_CN/q18_02.rb: -------------------------------------------------------------------------------- 1 | def check(last_n, used, list) 2 | # 已经全部使用,如果和最初的“1”相加能得到平方数,则结束递归 3 | return [1] if used.all? && (list[1].include?(last_n)) 4 | list[last_n].each{|i| # 逐一尝试候补数字 5 | if used[i - 1] == false then # 没有全部使用的情况 6 | used[i - 1] = true 7 | result = check(i, used, list) 8 | # 找到的时候,添加这个值 9 | return [i] + result if result.size > 0 10 | used[i - 1] = false 11 | end 12 | } 13 | [] 14 | end 15 | 16 | n = 2 17 | while true do 18 | square = (2..Math.sqrt(n * 2).floor).map{|i| i ** 2} 19 | # 找到可以作为相邻数字的候补数字 20 | list = {} 21 | (1..n).each{|i| 22 | list[i] = square.map{|s| s - i}.select{|s| s > 0} 23 | } 24 | # 把“1”设置为已使用,从“1”开始搜索 25 | result = check(1, [true] + [false] * (n - 1), list) 26 | break if result.size > 0 27 | n += 1 28 | end 29 | puts n 30 | p result 31 | -------------------------------------------------------------------------------- /ja_JP/q13_03.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (0..9).to_a.permutation(6){|e, a, d, t, k, l| 3 | if ((a + t == 8) || (a + t == 9) || (a + t == 10)) && 4 | ((a + e == 8) || (a + e == 9) || (a + e == 10)) && 5 | ((d + e + k) % 10 == l) && 6 | (((a + t + l) * 10 + d + e + k) % 100 == l * 11) then 7 | ((0..9).to_a - [k, e, d, l, t, a]).permutation(4){|i, r, s, w| 8 | if ((r != 0) && (w != 0) && (t != 0)) && 9 | ((s == w + 1) || (s == w + 2)) then 10 | read = r * 1000 + e * 100 + a * 10 + d 11 | write = w * 10000 + r * 1000 + i * 100 + t * 10 + e 12 | talk = t * 1000 + a * 100 + l * 10 + k 13 | skill = s * 10000 + k * 1000 + i * 100 + l * 10 + l 14 | if read + write + talk == skill then 15 | puts "#{read} + #{write} + #{talk} = #{skill}" 16 | count += 1 17 | end 18 | end 19 | } 20 | end 21 | } 22 | puts count 23 | -------------------------------------------------------------------------------- /ja_JP/q31_01.js: -------------------------------------------------------------------------------- 1 | var square = 6; 2 | var count = 0; 3 | var is_used = new Array(); 4 | for (var i = 0; i <= square; i++){ 5 | is_used[i] = new Array(); 6 | for (var j = 0; j <= square; j++){ 7 | is_used[i][j] = new Array(false, false); 8 | } 9 | } 10 | function route(x, y, is_first_time){ 11 | if ((x == square) && (y == square)){ 12 | if (is_first_time){ 13 | route(0, 0, false); 14 | } else { 15 | count++; 16 | } 17 | } 18 | if (x < square){ 19 | if (!is_used[x][y][0]){ 20 | is_used[x][y][0] = true; 21 | route(x + 1, y, is_first_time); 22 | is_used[x][y][0] = false; 23 | } 24 | } 25 | if (y < square){ 26 | if (!is_used[x][y][1]){ 27 | is_used[x][y][1] = true; 28 | route(x, y + 1, is_first_time); 29 | is_used[x][y][1] = false; 30 | } 31 | } 32 | } 33 | route(0, 0, true); 34 | console.log(count); 35 | -------------------------------------------------------------------------------- /zh_CN/q13_03.rb: -------------------------------------------------------------------------------- 1 | count = 0 2 | (0..9).to_a.permutation(6){|e, a, d, t, k, l| 3 | if ((a + t == 8) || (a + t == 9) || (a + t == 10)) && 4 | ((a + e == 8) || (a + e == 9) || (a + e == 10)) && 5 | ((d + e + k) % 10 == l) && 6 | (((a + t + l) * 10 + d + e + k) % 100 == l * 11) then 7 | ((0..9).to_a - [k, e, d, l, t, a]).permutation(4){|i, r, s, w| 8 | if ((r != 0) && (w != 0) && (t != 0)) && 9 | ((s == w + 1) || (s == w + 2)) then 10 | read = r * 1000 + e * 100 + a * 10 + d 11 | write = w * 10000 + r * 1000 + i * 100 + t * 10 + e 12 | talk = t * 1000 + a * 100 + l * 10 + k 13 | skill = s * 10000 + k * 1000 + i * 100 + l * 10 + l 14 | if read + write + talk == skill then 15 | puts "#{read} + #{write} + #{talk} = #{skill}" 16 | count += 1 17 | end 18 | end 19 | } 20 | end 21 | } 22 | puts count 23 | -------------------------------------------------------------------------------- /zh_CN/q31_01.js: -------------------------------------------------------------------------------- 1 | var square = 6; 2 | var count = 0; 3 | var is_used = new Array(); 4 | for (var i = 0; i <= square; i++){ 5 | is_used[i] = new Array(); 6 | for (var j = 0; j <= square; j++){ 7 | is_used[i][j] = new Array(false, false); 8 | } 9 | } 10 | function route(x, y, is_first_time){ 11 | if ((x == square) && (y == square)){ 12 | if (is_first_time){ 13 | route(0, 0, false); 14 | } else { 15 | count++; 16 | } 17 | } 18 | if (x < square){ 19 | if (!is_used[x][y][0]){ 20 | is_used[x][y][0] = true; 21 | route(x + 1, y, is_first_time); 22 | is_used[x][y][0] = false; 23 | } 24 | } 25 | if (y < square){ 26 | if (!is_used[x][y][1]){ 27 | is_used[x][y][1] = true; 28 | route(x, y + 1, is_first_time); 29 | is_used[x][y][1] = false; 30 | } 31 | } 32 | } 33 | route(0, 0, true); 34 | console.log(count); 35 | -------------------------------------------------------------------------------- /ja_JP/q59_01.rb: -------------------------------------------------------------------------------- 1 | # 人数 2 | @n = 8 3 | # 最短移動距離 4 | @min_step = 98 5 | # ゴール 6 | @goal = [] 7 | (1..@n).each{|i| 8 | @goal << (1..@n).to_a.reverse.rotate(i) 9 | } 10 | 11 | def search(child, oni, oni_pos, step, log) 12 | if oni == 0 then # 最初の鬼が円から外れたとき 13 | if @goal.include?(child) then 14 | puts "#{step} #{log}" # 移動距離と鬼が座った位置を表示 15 | @min_step = [step, @min_step].min 16 | return 17 | end 18 | end 19 | (1..(@n - 1)).each{|i| # 現在の鬼の位置から順に探索 20 | if step + @n + i <= @min_step then 21 | next_child = child.clone 22 | pos = (oni_pos + i) % @n # 次の鬼の位置 23 | next_child[pos] = oni # 鬼が座る 24 | next_oni = child[pos] # 次の鬼が外に出る 25 | search(next_child, next_oni, pos, 26 | step + @n + i, log + pos.to_s) 27 | end 28 | } 29 | end 30 | 31 | # 最初は1の位置に鬼が入る 32 | search([0] + (2..@n).to_a, 1, 0, @n, "0") 33 | -------------------------------------------------------------------------------- /ja_JP/q10_01.rb: -------------------------------------------------------------------------------- 1 | european = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 2 | 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 3 | 22, 18, 29, 7, 28, 12, 35, 3, 26] 4 | american = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 5 | 3, 24, 36, 13, 1, 00, 27, 10, 25, 29, 12, 8, 19, 31, 6 | 18, 6, 21, 33, 16, 4, 23, 35, 14, 2] 7 | 8 | def sum_max(roulette, n) 9 | ans = 0 10 | roulette.size.times{|i| 11 | tmp = 0 12 | if i + n <= roulette.size then 13 | # 配列の両端をまたがない場合 14 | tmp = roulette[i, n].inject(:+) 15 | else 16 | # 配列の両端をまたぐ場合 17 | tmp = roulette[0, (i + n) % roulette.size].inject(:+) 18 | tmp += roulette[i..-1].inject(:+) 19 | end 20 | ans = [ans, tmp].max 21 | } 22 | ans 23 | end 24 | 25 | cnt = 0 26 | (2..36).each{|i| 27 | cnt += 1 if sum_max(european, i) < sum_max(american, i) 28 | } 29 | puts cnt 30 | -------------------------------------------------------------------------------- /zh_CN/q10_01.rb: -------------------------------------------------------------------------------- 1 | european = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 2 | 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 3 | 22, 18, 29, 7, 28, 12, 35, 3, 26] 4 | american = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 5 | 3, 24, 36, 13, 1, 00, 27, 10, 25, 29, 12, 8, 19, 31, 6 | 18, 6, 21, 33, 16, 4, 23, 35, 14, 2] 7 | 8 | def sum_max(roulette, n) 9 | ans = 0 10 | roulette.size.times{|i| 11 | tmp = 0 12 | if i + n <= roulette.size then 13 | # 不包含数组两端元素的情况 14 | tmp = roulette[i, n].inject(:+) 15 | else 16 | # 包含数组两端元素的情况 17 | tmp = roulette[0, (i + n) % roulette.size].inject(:+) 18 | tmp += roulette[i..-1].inject(:+) 19 | end 20 | ans = [ans, tmp].max 21 | } 22 | ans 23 | end 24 | 25 | cnt = 0 26 | (2..36).each{|i| 27 | cnt += 1 if sum_max(european, i) < sum_max(american, i) 28 | } 29 | puts cnt 30 | -------------------------------------------------------------------------------- /zh_CN/q54_02.rb: -------------------------------------------------------------------------------- 1 | N = 10 2 | 3 | # 加到原始数(比特列)后,返回算珠移动个数 4 | def move(bit, add) 5 | base = 0 6 | N.times{|i| 7 | base += i + 1 if (bit & (1 << i)) > 0 8 | } 9 | 10 | # 确认十位上5的算珠位置 11 | a0, a1 = (base + add).divmod(50) 12 | b0, b1 = base.divmod(50) 13 | 14 | # 确认十位上1的算珠位置 15 | a2, a3 = a1.divmod(10) 16 | b2, b3 = b1.divmod(10) 17 | 18 | # 确认个位上算珠的位置 19 | a4, a5 = a3.divmod(5) 20 | b4, b5 = b3.divmod(5) 21 | 22 | # 由所有位置差相加计算移动量 23 | (a0 - b0).abs + (a2 - b2).abs + (a4 - b4).abs + (a5 - b5).abs 24 | end 25 | 26 | @memo = Hash.new(0) 27 | @memo[(1 << N) - 1] = 0 28 | 29 | # 求从1~10求和时,最少的算珠移动量 30 | def search(bit) 31 | return @memo[bit] if @memo.has_key?(bit) 32 | min = 1000 33 | N.times{|i| 34 | if bit & (1 << i) == 0 then 35 | min = [min, move(bit, i + 1) + search(bit | (1 << i))].min 36 | end 37 | } 38 | @memo[bit] = min 39 | end 40 | 41 | puts search(0) 42 | -------------------------------------------------------------------------------- /zh_CN/q68_01.rb: -------------------------------------------------------------------------------- 1 | # 为座位从1~30编号 2 | seats = (1..30).to_a 3 | # 不符合条件的座次安排要排除 4 | ng = [[1, 2, 7], [5, 6, 12], [19, 25, 26], [24, 29, 30], 5 | [1, 2, 3, 8], [2, 3, 4, 9], [3, 4, 5, 10], 6 | [4, 5, 6, 11], [1, 7, 8, 13], [7, 13, 14, 19], 7 | [13, 19, 20, 25], [6, 11, 12, 18], [12, 17, 18, 24], 8 | [18, 23, 24, 30], [20, 25, 26, 27], [21, 26, 27, 28], 9 | [22, 27, 28, 29], [23, 28, 29, 30], 10 | [2, 7, 8, 9, 14], [3, 8, 9, 10, 15], [4, 9, 10, 11, 16], 11 | [5, 10, 11, 12, 17], [8, 13, 14, 15, 20], [9, 14, 15, 16, 21], 12 | [10, 15, 16, 17, 22], [11, 16, 17, 18, 23], 13 | [14, 19, 20, 21, 26], [15, 20, 21, 22, 27], 14 | [16, 21, 22, 23, 28], [17, 22, 23, 24, 29]] 15 | 16 | cnt = 0 17 | seats.combination(15){|boy| # 男生的座次安排组合 18 | girl = seats - boy # 女生的座次安排组合 19 | if ng.all?{|n| boy & n != n} && ng.all?{|n| girl & n != n} then 20 | cnt += 1 21 | end 22 | } 23 | p cnt 24 | -------------------------------------------------------------------------------- /ja_JP/q61_01.rb: -------------------------------------------------------------------------------- 1 | # 盤面のサイズ 2 | W, H = 5, 4 3 | 4 | def check(color, del) 5 | color.delete(del) 6 | # 移動先をセット 7 | left, right, up, down = del - 1, del + 1, del - W, del + W 8 | # 移動先に同じ色があればその方向を探索 9 | check(color, left) if (del % W > 0) && color.include?(left) 10 | check(color, right) if (del % W != W - 1) && color.include?(right) 11 | check(color, up) if (del / W > 0) && color.include?(up) 12 | check(color, down) if (del / W != H - 1) && color.include?(down) 13 | end 14 | 15 | # 盤面の初期化 16 | map = (0.. W*H-1).to_a 17 | count = 0 18 | map.combination(W * H / 2){|blue| # 半分を青にする 19 | if blue.include?(0) then # 左上は青に固定 20 | white = map - blue # 残りが白 21 | check(blue, blue[0]) # 青がつながっているか 22 | check(white, white[0]) if blue.size == 0 # 白がつながっているか 23 | count += 1 if white.size == 0 # 両方つながっていればカウント 24 | end 25 | } 26 | puts count 27 | -------------------------------------------------------------------------------- /ja_JP/q69_01.rb: -------------------------------------------------------------------------------- 1 | # 座席に1 〜30の番号を付与 2 | seats = (1..30).to_a 3 | # 条件を満たさない配置は除外対象 4 | ng = [[1, 2, 7], [5, 6, 12], [19, 25, 26], [24, 29, 30], 5 | [1, 2, 3, 8], [2, 3, 4, 9], [3, 4, 5, 10], 6 | [4, 5, 6, 11], [1, 7, 8, 13], [7, 13, 14, 19], 7 | [13, 19, 20, 25], [6, 11, 12, 18], [12, 17, 18, 24], 8 | [18, 23, 24, 30], [20, 25, 26, 27], [21, 26, 27, 28], 9 | [22, 27, 28, 29], [23, 28, 29, 30], 10 | [2, 7, 8, 9, 14], [3, 8, 9, 10, 15], [4, 9, 10, 11, 16], 11 | [5, 10, 11, 12, 17], [8, 13, 14, 15, 20], [9, 14, 15, 16, 21], 12 | [10, 15, 16, 17, 22], [11, 16, 17, 18, 23], 13 | [14, 19, 20, 21, 26], [15, 20, 21, 22, 27], 14 | [16, 21, 22, 23, 28], [17, 22, 23, 24, 29]] 15 | 16 | cnt = 0 17 | seats.combination(15){|boy| # 男子の配置の組み合わせ 18 | girl = seats - boy # 女子の配置の組み合わせ 19 | if ng.all?{|n| boy & n != n} && ng.all?{|n| girl & n != n} then 20 | cnt += 1 21 | end 22 | } 23 | p cnt 24 | -------------------------------------------------------------------------------- /zh_CN/q60_01.rb: -------------------------------------------------------------------------------- 1 | # 长方形大小 2 | W, H = 5, 4 3 | 4 | def check(color, del) 5 | color.delete(del) 6 | # 设置移动方向 7 | left, right, up, down = del - 1, del + 1, del - W, del + W 8 | # 如果移动方向上有相同颜色,则继续向这个方向搜索 9 | check(color, left) if (del % W > 0) && color.include?(left) 10 | check(color, right) if (del % W != W - 1) && color.include?(right) 11 | check(color, up) if (del / W > 0) && color.include?(up) 12 | check(color, down) if (del / W != H - 1) && color.include?(down) 13 | end 14 | 15 | # 初始化长方形 16 | map = (0.. W*H-1).to_a 17 | count = 0 18 | map.combination(W * H / 2){|blue| # 把一半标为蓝色 19 | if blue.include?(0) then # 左上角固定为蓝色 20 | white = map - blue # 剩下的是白色 21 | check(blue, blue[0]) # 蓝色是否互相连接 22 | check(white, white[0]) if blue.size == 0 # 白色是否互相连接 23 | count += 1 if white.size == 0 # 如果两种颜色都符合条件则计入结果 24 | end 25 | } 26 | puts count 27 | -------------------------------------------------------------------------------- /ja_JP/q55_02.rb: -------------------------------------------------------------------------------- 1 | N = 10 2 | 3 | # 元の数(ビット列)に加算した場合に移動する量を返す 4 | def move(bit, add) 5 | base = 0 6 | N.times{|i| 7 | base += i + 1 if (bit & (1 << i)) > 0 8 | } 9 | 10 | # 10の位の5の玉の位置を確認 11 | a0, a1 = (base + add).divmod(50) 12 | b0, b1 = base.divmod(50) 13 | 14 | # 10の位の1の玉の位置を確認 15 | a2, a3 = a1.divmod(10) 16 | b2, b3 = b1.divmod(10) 17 | 18 | # 1の位の玉の位置を確認 19 | a4, a5 = a3.divmod(5) 20 | b4, b5 = b3.divmod(5) 21 | 22 | # すべての位置の差から動かす量を加算 23 | (a0 - b0).abs + (a2 - b2).abs + (a4 - b4).abs + (a5 - b5).abs 24 | end 25 | 26 | @memo = Hash.new(0) 27 | @memo[(1 << N) - 1] = 0 28 | 29 | # 10まで足したときの移動量が最少になるときを求める 30 | def search(bit) 31 | return @memo[bit] if @memo.has_key?(bit) 32 | min = 1000 33 | N.times{|i| 34 | if bit & (1 << i) == 0 then 35 | min = [min, move(bit, i + 1) + search(bit | (1 << i))].min 36 | end 37 | } 38 | @memo[bit] = min 39 | end 40 | 41 | puts search(0) 42 | -------------------------------------------------------------------------------- /zh_CN/q37_03.rb: -------------------------------------------------------------------------------- 1 | # 定义表示0〜9数字的比特序列 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 事先得出异或运算结果 6 | @flip = Array.new(10) 7 | (0..9).each{|i| 8 | @flip[i] = Array.new(10) 9 | (0..9).each{|j| 10 | @flip[i][j] = (bit[i]^bit[j]).to_s(2).count("1") 11 | } 12 | } 13 | 14 | # 每次设置翻转比特序列的值为初始值 15 | @min = 63 16 | 17 | # 递归检索 18 | # is_used: 各数字是否已使用 19 | # sum: 已使用数字的翻转次数 20 | # prev: 上一次使用的数字 21 | def search(is_used, sum, prev) 22 | if is_used.count(false) == 0 then 23 | @min = sum 24 | else 25 | 10.times{|i| 26 | if !is_used[i] then 27 | is_used[i] = true 28 | next_sum = 0 29 | next_sum = sum + @flip[prev][i] if prev >= 0 30 | search(is_used, next_sum, i) if @min > next_sum 31 | is_used[i] = false 32 | end 33 | } 34 | end 35 | end 36 | search(Array.new(10, false), 0, -1) 37 | puts @min 38 | -------------------------------------------------------------------------------- /ja_JP/q38_03.rb: -------------------------------------------------------------------------------- 1 | # 0〜9を表すビットを定義 2 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 3 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011] 4 | 5 | # 排他的論理和の結果を先に算出 6 | @flip = Array.new(10) 7 | (0..9).each{|i| 8 | @flip[i] = Array.new(10) 9 | (0..9).each{|j| 10 | @flip[i][j] = (bit[i]^bit[j]).to_s(2).count("1") 11 | } 12 | } 13 | 14 | # 毎回全ビットを反転させた値を初期値とする 15 | @min = 63 16 | 17 | # 再帰的に探索する 18 | # is_used : 各数字が使用済みかどうか 19 | # sum : 使用した数字での反転数 20 | # prev : 前回に使用した数字 21 | def search(is_used, sum, prev) 22 | if is_used.count(false) == 0 then 23 | @min = sum 24 | else 25 | 10.times{|i| 26 | if !is_used[i] then 27 | is_used[i] = true 28 | next_sum = 0 29 | next_sum = sum + @flip[prev][i] if prev >= 0 30 | search(is_used, next_sum, i) if @min > next_sum 31 | is_used[i] = false 32 | end 33 | } 34 | end 35 | end 36 | search(Array.new(10, false), 0, -1) 37 | puts @min 38 | -------------------------------------------------------------------------------- /zh_CN/q64_01.rb: -------------------------------------------------------------------------------- 1 | # 6组对手 2 | PAIR = 6 3 | 4 | # 设置起始和终止状态 5 | start = (1..PAIR * 2 - 1).to_a + [0] 6 | goal = [0] + (2..PAIR * 2 - 1).to_a + [1] 7 | 8 | # 获取投接球状态列表 9 | def throwable(balls) 10 | result = [] 11 | balls.each{|ball| 12 | c = ball.index(0) # 获取接球手位置 13 | p = (c + PAIR) % (PAIR * 2) # 计算接球手对面位置 14 | [-1, 0, 1].each{|d| # 正对面及其左右 15 | if (p + d) / PAIR == p / PAIR then 16 | ball[c], ball[p + d] = ball[p + d], ball[c] 17 | result.push(ball.clone) # 设置投球结果 18 | ball[c], ball[p + d] = ball[p + d], ball[c] 19 | end 20 | } 21 | } 22 | result 23 | end 24 | 25 | # 设定初始状态 26 | balls = [start] 27 | log = [start] 28 | cnt = 0 29 | # 广度优先搜索 30 | while !balls.include?(goal) do 31 | next_balls = throwable(balls) # 获取下一步 32 | balls = next_balls - log # 选择之前没有出现过的投球方案 33 | log |= next_balls # 添加投球结果 34 | cnt += 1 35 | end 36 | puts cnt 37 | -------------------------------------------------------------------------------- /zh_CN/q44_02.rb: -------------------------------------------------------------------------------- 1 | require "prime" 2 | 3 | # 获取3位的质数 4 | primes = Prime.each(1000).select{|i| i >= 100} 5 | 6 | # 以首位数字生成哈希表 7 | prime_h = {0 => []} 8 | primes.chunk{|c| c / 100}.each{|k, v| 9 | prime_h[k] = v 10 | } 11 | 12 | cnt = 0 13 | primes.each{|r1| # 第1行 14 | prime_h[r1 / 100].each{|c1| # 第1列 15 | prime_h[(c1 % 100) / 10].each{|r2| # 第2行 16 | prime_h[(r1 % 100) / 10].each{|c2| # 第2列 17 | if (r2 % 100) / 10 == (c2 % 100) / 10 then # 中心点 18 | prime_h[c1 % 10].each{|r3| # 第3行 19 | if c2 % 10 == (r3 % 100) / 10 then 20 | c3 = (r1 % 10) * 100 + (r2 % 10) * 10 + (r3 % 10) 21 | if primes.include?(c3) then # 第3列是不是质数 22 | cnt += 1 if [r1, r2, r3, c1, c2, c3].uniq.size == 6 23 | end 24 | end 25 | } 26 | end 27 | } 28 | } 29 | } 30 | } 31 | puts cnt 32 | -------------------------------------------------------------------------------- /ja_JP/q45_02.rb: -------------------------------------------------------------------------------- 1 | require "prime" 2 | 3 | # 3桁の素数を取得 4 | primes = Prime.each(1000).select{|i| i >= 100} 5 | 6 | # 先頭の桁でハッシュを作成 7 | prime_h = {0 => []} 8 | primes.chunk{|c| c / 100}.each{|k, v| 9 | prime_h[k] = v 10 | } 11 | 12 | cnt = 0 13 | primes.each{|r1| # 1行目 14 | prime_h[r1 / 100].each{|c1| # 1列目 15 | prime_h[(c1 % 100) / 10].each{|r2| # 2行目 16 | prime_h[(r1 % 100) / 10].each{|c2| # 2列目 17 | if (r2 % 100) / 10 == (c2 % 100) / 10 then # 中央の点 18 | prime_h[c1 % 10].each{|r3| # 3行目 19 | if c2 % 10 == (r3 % 100) / 10 then 20 | c3 = (r1 % 10) * 100 + (r2 % 10) * 10 + (r3 % 10) 21 | if primes.include?(c3) then # 3列目が素数か 22 | cnt += 1 if [r1, r2, r3, c1, c2, c3].uniq.size == 6 23 | end 24 | end 25 | } 26 | end 27 | } 28 | } 29 | } 30 | } 31 | puts cnt 32 | -------------------------------------------------------------------------------- /ja_JP/q65_01.rb: -------------------------------------------------------------------------------- 1 | # ペアは6組 2 | PAIR = 6 3 | 4 | # 開始と終了を設定 5 | start = (1..PAIR * 2 - 1).to_a + [0] 6 | goal = [0] + (2..PAIR * 2 - 1).to_a + [1] 7 | 8 | # 投げられる一覧を取得 9 | def throwable(balls) 10 | result = [] 11 | balls.each{|ball| 12 | c = ball.index(0) # 受け手の位置を取得 13 | p = (c + PAIR) % (PAIR * 2) # 受け手の正面を計算 14 | [-1, 0, 1].each{|d| # 正面と左右 15 | if (p + d) / PAIR == p / PAIR then 16 | ball[c], ball[p + d] = ball[p + d], ball[c] 17 | result.push(ball.clone) # 投げた結果をセット 18 | ball[c], ball[p + d] = ball[p + d], ball[c] 19 | end 20 | } 21 | } 22 | result 23 | end 24 | 25 | # 初期状態を設定 26 | balls = [start] 27 | log = [start] 28 | cnt = 0 29 | # 幅優先探索を実行 30 | while !balls.include?(goal) do 31 | next_balls = throwable(balls) # 次のステップを取得 32 | balls = next_balls - log # 過去に現れていないものを選択 33 | log |= next_balls # 投げた結果を追加 34 | cnt += 1 35 | end 36 | puts cnt 37 | -------------------------------------------------------------------------------- /ja_JP/q26_02.rb: -------------------------------------------------------------------------------- 1 | W, H = 10, 10 2 | parking = [9] * (W + 1) + ([1] * W + [9]) * H + [9] * (W + 1) 3 | 4 | @goal = parking.clone 5 | @goal[W + 1] = 2 6 | start = parking.clone 7 | start[- W - 3] = 2 8 | 9 | def search(prev, depth) 10 | target = [] 11 | prev.each{|parking, pos| 12 | [-1, 1, W + 1, - W - 1].each{|d| 13 | dd = pos + d 14 | if (parking[dd] != 9) then 15 | temp = parking.clone 16 | temp[dd], temp[pos] = temp[pos], temp[dd] 17 | if !@log.has_key?([temp, dd]) then 18 | target.push([temp, dd]) 19 | @log[[temp,dd]] = depth + 1 20 | end 21 | end 22 | } 23 | } 24 | return if target.include?([@goal, (W + 1) * (H + 1) - 2]) 25 | search(target, depth + 1) if target.size > 0 26 | end 27 | 28 | @log = {} 29 | @log[[start, (W + 1) * H - 2]] = 0 30 | @log[[start, (W + 1) * (H + 1) - 3]] = 0 31 | 32 | search([[start, (W+1) * H - 2], [start, (W+1) * (H+1) - 3]], 0) 33 | puts @log[[@goal, (W + 1) * (H + 1) - 2]] 34 | -------------------------------------------------------------------------------- /zh_CN/q26_02.rb: -------------------------------------------------------------------------------- 1 | W, H = 10, 10 2 | parking = [9] * (W + 1) + ([1] * W + [9]) * H + [9] * (W + 1) 3 | 4 | @goal = parking.clone 5 | @goal[W + 1] = 2 6 | start = parking.clone 7 | start[- W - 3] = 2 8 | 9 | def search(prev, depth) 10 | target = [] 11 | prev.each{|parking, pos| 12 | [-1, 1, W + 1, - W - 1].each{|d| 13 | dd = pos + d 14 | if (parking[dd] != 9) then 15 | temp = parking.clone 16 | temp[dd], temp[pos] = temp[pos], temp[dd] 17 | if !@log.has_key?([temp, dd]) then 18 | target.push([temp, dd]) 19 | @log[[temp,dd]] = depth + 1 20 | end 21 | end 22 | } 23 | } 24 | return if target.include?([@goal, (W + 1) * (H + 1) - 2]) 25 | search(target, depth + 1) if target.size > 0 26 | end 27 | 28 | @log = {} 29 | @log[[start, (W + 1) * H - 2]] = 0 30 | @log[[start, (W + 1) * (H + 1) - 3]] = 0 31 | 32 | search([[start, (W+1) * H - 2], [start, (W+1) * (H+1) - 3]], 0) 33 | puts @log[[@goal, (W + 1) * (H + 1) - 2]] 34 | -------------------------------------------------------------------------------- /ja_JP/q30_01.rb: -------------------------------------------------------------------------------- 1 | N = 20 2 | 3 | def set_tap(remain) 4 | return 1 if remain == 1 5 | cnt = 0 6 | # 2口 7 | (1..(remain / 2)).each{|i| 8 | if remain - i == i then 9 | cnt += set_tap(i) * (set_tap(i) + 1) / 2 10 | else 11 | cnt += set_tap(remain - i) * set_tap(i) 12 | end 13 | } 14 | # 3口 15 | (1..(remain / 3)).each{|i| 16 | (i..((remain - i) / 2)).each{|j| 17 | if (remain - (i + j) == i) && (i == j) then 18 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 19 | elsif remain - (i + j) == i then 20 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 21 | elsif i == j then 22 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 23 | elsif remain - (i + j) == j then 24 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 25 | else 26 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) 27 | end 28 | } 29 | } 30 | cnt 31 | end 32 | 33 | puts set_tap(N) 34 | -------------------------------------------------------------------------------- /zh_CN/q30_01.rb: -------------------------------------------------------------------------------- 1 | N = 20 2 | 3 | def set_tap(remain) 4 | return 1 if remain == 1 5 | cnt = 0 6 | # 2插口 7 | (1..(remain / 2)).each{|i| 8 | if remain - i == i then 9 | cnt += set_tap(i) * (set_tap(i) + 1) / 2 10 | else 11 | cnt += set_tap(remain - i) * set_tap(i) 12 | end 13 | } 14 | # 3插口 15 | (1..(remain / 3)).each{|i| 16 | (i..((remain - i) / 2)).each{|j| 17 | if (remain - (i + j) == i) && (i == j) then 18 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 19 | elsif remain - (i + j) == i then 20 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 21 | elsif i == j then 22 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 23 | elsif remain - (i + j) == j then 24 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 25 | else 26 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) 27 | end 28 | } 29 | } 30 | cnt 31 | end 32 | 33 | puts set_tap(N) 34 | -------------------------------------------------------------------------------- /zh_CN/q48_02.js: -------------------------------------------------------------------------------- 1 | const N = 8; /* 各色卡片数目 */ 2 | var start = (1 << N) - 1; /* 开始状态(0N个,1N个) */ 3 | var mask = (1 << N * 2) - 1; /* 掩码 */ 4 | 5 | /* 目标状态(0和1交错排列) */ 6 | var goal1 = 0; 7 | for (var i = 0; i < N; i++){ goal1 = (goal1 << 2) + 1; } 8 | var goal2 = mask - goal1; 9 | 10 | /* 对值为1的数位进行计数 */ 11 | function bitcount(x) { 12 | x = (x & 0x55555555) + (x >> 1 & 0x55555555); 13 | x = (x & 0x33333333) + (x >> 2 & 0x33333333); 14 | x = (x & 0x0F0F0F0F) + (x >> 4 & 0x0F0F0F0F); 15 | x = (x & 0x00FF00FF) + (x >> 8 & 0x00FF00FF); 16 | x = (x & 0x0000FFFF) + (x >> 16 & 0x0000FFFF); 17 | return x; 18 | } 19 | 20 | /* 反转次数 */ 21 | var count = N * 2; 22 | for (var i = 0; i < (1 << N * 2); i++){ 23 | var turn = i ^ (i << 1) ^ (i << 2); 24 | turn = (turn ^ (turn >> (N * 2))) & mask; 25 | 26 | /* 到达目标状态后找出反转位置数字的最小值 */ 27 | if (((start ^ turn) == goal1) || ((start ^ turn) == goal2)){ 28 | if (count > bitcount(i)){ 29 | count = bitcount(i); 30 | } 31 | } 32 | } 33 | console.log(count); 34 | -------------------------------------------------------------------------------- /ja_JP/q49_02.js: -------------------------------------------------------------------------------- 1 | const N = 8; /* 各色の数 */ 2 | var start = (1 << N) - 1; /* 開始状態(0がN個、1がN個) */ 3 | var mask = (1 << N * 2) - 1; /* ビットマスク */ 4 | 5 | /* ゴール状態(0と1を交互に設定) */ 6 | var goal1 = 0; 7 | for (var i = 0; i < N; i++){ goal1 = (goal1 << 2) + 1; } 8 | var goal2 = mask - goal1; 9 | 10 | /* 1が立っているビットの数を数える */ 11 | function bitcount(x) { 12 | x = (x & 0x55555555) + (x >> 1 & 0x55555555); 13 | x = (x & 0x33333333) + (x >> 2 & 0x33333333); 14 | x = (x & 0x0F0F0F0F) + (x >> 4 & 0x0F0F0F0F); 15 | x = (x & 0x00FF00FF) + (x >> 8 & 0x00FF00FF); 16 | x = (x & 0x0000FFFF) + (x >> 16 & 0x0000FFFF); 17 | return x; 18 | } 19 | 20 | /* 交換回数 */ 21 | var count = N * 2; 22 | for (var i = 0; i < (1 << N * 2); i++){ 23 | var turn = i ^ (i << 1) ^ (i << 2); 24 | turn = (turn ^ (turn >> (N * 2))) & mask; 25 | 26 | /* ゴールと一致すれば交換する位置の数の最小値を判定 */ 27 | if (((start ^ turn) == goal1) || ((start ^ turn) == goal2)){ 28 | if (count > bitcount(i)){ 29 | count = bitcount(i); 30 | } 31 | } 32 | } 33 | console.log(count); 34 | -------------------------------------------------------------------------------- /zh_CN/q57_01.rb: -------------------------------------------------------------------------------- 1 | n = 14 2 | # 设置初始状态人数(a, b, c的人数+教师通话次数) 3 | status = [[n, 0, 0, 0]] 4 | step = 0 # 经过时间 5 | while status.select{|s| s[1] == n}.size == 0 do 6 | # 循环处理,直到不必通话的学生(b)人数变为总人数 7 | next_status = [] 8 | status.each{|s| 9 | (s[1] + 1).times{|b| 10 | # 不必通话的学生联系其他学生的人数 11 | (s[2] + 1).times{|c| 12 | # 需要通话的学生联系的人数 13 | if s[2] > 0 then # 有可通话学生的时候 14 | # 有学生联系教师 15 | if s[0]-b-c+1 >= 0 then 16 | next_status << [s[0]-b-c+1, s[1]+c, s[2]+b-1, s[3]+1] 17 | end 18 | end 19 | # 没有学生联系教师 20 | if s[0]-b-c >= 0 then 21 | next_status << [s[0]-b-c, s[1]+c, s[2]+b, s[3]] 22 | end 23 | # 教师联系了学生 24 | if s[0]-b-c-1 >= 0 then 25 | next_status << [s[0]-b-c-1, s[1]+c+1, s[2]+b, s[3]+1] 26 | end 27 | } 28 | } 29 | } 30 | status = (next_status - status).uniq 31 | step += 1 32 | end 33 | # 打印经过时间 34 | puts step 35 | # 打印在最短时间的情况中,教师通话次数最少的情况 36 | p status.select{|s| s[1] == n}.min{|a, b| a[3] <=> b[3]} 37 | -------------------------------------------------------------------------------- /ja_JP/q30_02.rb: -------------------------------------------------------------------------------- 1 | N = 20 2 | 3 | @memo = {1 => 1} 4 | def set_tap(remain) 5 | return @memo[remain] if @memo.has_key?(remain) 6 | cnt = 0 7 | # 2口 8 | (1..(remain / 2)).each{|i| 9 | if remain - i == i then 10 | cnt += set_tap(i) * (set_tap(i) + 1) / 2 11 | else 12 | cnt += set_tap(remain - i) * set_tap(i) 13 | end 14 | } 15 | # 3口 16 | (1..(remain / 3)).each{|i| 17 | (i..((remain - i) / 2)).each{|j| 18 | if (remain - (i + j) == i) && (i == j) then 19 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 20 | elsif remain - (i + j) == i then 21 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 22 | elsif i == j then 23 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 24 | elsif remain - (i + j) == j then 25 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 26 | else 27 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) 28 | end 29 | } 30 | } 31 | @memo[remain] = cnt 32 | end 33 | 34 | puts set_tap(N) 35 | -------------------------------------------------------------------------------- /zh_CN/q30_02.rb: -------------------------------------------------------------------------------- 1 | N = 20 2 | 3 | @memo = {1 => 1} 4 | def set_tap(remain) 5 | return @memo[remain] if @memo.has_key?(remain) 6 | cnt = 0 7 | # 2插口 8 | (1..(remain / 2)).each{|i| 9 | if remain - i == i then 10 | cnt += set_tap(i) * (set_tap(i) + 1) / 2 11 | else 12 | cnt += set_tap(remain - i) * set_tap(i) 13 | end 14 | } 15 | # 3插口 16 | (1..(remain / 3)).each{|i| 17 | (i..((remain - i) / 2)).each{|j| 18 | if (remain - (i + j) == i) && (i == j) then 19 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 20 | elsif remain - (i + j) == i then 21 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 22 | elsif i == j then 23 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 24 | elsif remain - (i + j) == j then 25 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 26 | else 27 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) 28 | end 29 | } 30 | } 31 | @memo[remain] = cnt 32 | end 33 | 34 | puts set_tap(N) 35 | -------------------------------------------------------------------------------- /zh_CN/q33_01.rb: -------------------------------------------------------------------------------- 1 | # 设置棋盘 2 | @board = Array.new(11).map!{Array.new(11)} 3 | (0..10).each{|i| 4 | (0..10).each{|j| 5 | @board[i][j] = (i == 0) || (i == 10) || (j == 0) || (j == 10) 6 | } 7 | } 8 | 9 | # 初始化统计变量 10 | count = 0 11 | 12 | # 递归遍历 13 | def search(x, y, dx, dy) 14 | return if @board[x][y] 15 | @check[x * 10 + y] = 1 16 | search(x + dx, y + dy, dx, dy) 17 | end 18 | 19 | # 按顺序放置飞车和角行进行遍历 20 | (1..9).each{|hy| 21 | (1..9).each{|hx| 22 | (1..9).each{|ky| 23 | (1..9).each{|kx| 24 | if (hx != kx) || (hy != ky) then 25 | @check = Hash.new() 26 | @board[hx][hy] = @board[kx][ky] = true 27 | [[-1, 0], [1, 0], [0, -1], [0, 1]].each{|hd| 28 | search(hx+hd[0], hy+hd[1], hd[0], hd[1]) 29 | } 30 | [[-1, -1], [-1, 1], [1, -1], [1, 1]].each{|kd| 31 | search(kx+kd[0], ky+kd[1], kd[0], kd[1]) 32 | } 33 | @board[hx][hy] = @board[kx][ky] = false 34 | count += @check.size 35 | end 36 | } 37 | } 38 | } 39 | } 40 | puts count 41 | -------------------------------------------------------------------------------- /ja_JP/q34_01.rb: -------------------------------------------------------------------------------- 1 | # 盤面の設定 2 | @board = Array.new(11).map!{Array.new(11)} 3 | (0..10).each{|i| 4 | (0..10).each{|j| 5 | @board[i][j] = (i == 0) || (i == 10) || (j == 0) || (j == 10) 6 | } 7 | } 8 | 9 | # 集計フィールドの初期化 10 | count = 0 11 | 12 | # 再帰的に探索 13 | def search(x, y, dx, dy) 14 | return if @board[x][y] 15 | @check[x * 10 + y] = 1 16 | search(x + dx, y + dy, dx, dy) 17 | end 18 | 19 | # 飛車、角を順に設定して探索 20 | (1..9).each{|hy| 21 | (1..9).each{|hx| 22 | (1..9).each{|ky| 23 | (1..9).each{|kx| 24 | if (hx != kx) || (hy != ky) then 25 | @check = Hash.new() 26 | @board[hx][hy] = @board[kx][ky] = true 27 | [[-1, 0], [1, 0], [0, -1], [0, 1]].each{|hd| 28 | search(hx+hd[0], hy+hd[1], hd[0], hd[1]) 29 | } 30 | [[-1, -1], [-1, 1], [1, -1], [1, 1]].each{|kd| 31 | search(kx+kd[0], ky+kd[1], kd[0], kd[1]) 32 | } 33 | @board[hx][hy] = @board[kx][ky] = false 34 | count += @check.size 35 | end 36 | } 37 | } 38 | } 39 | } 40 | puts count 41 | -------------------------------------------------------------------------------- /ja_JP/q58_01.rb: -------------------------------------------------------------------------------- 1 | n = 14 2 | # 初期状態の人数をセット(a, b, cの人数 + 先生が電話した回数) 3 | status = [[n, 0, 0, 0]] 4 | step = 0 # 経過時間 5 | while status.select{|s| s[1] == n}.size == 0 do 6 | # 連絡が不要な生徒(b)が全員になるまで以下を繰り返す 7 | next_status = [] 8 | status.each{|s| 9 | (s[1] + 1).times{|b| 10 | # 連絡が不要な生徒が他の生徒に連絡する人数 11 | (s[2] + 1).times{|c| 12 | # 連絡が必要な生徒が連絡する人数 13 | if s[2] > 0 then # 発信できる生徒がいるとき 14 | # 生徒から先生あり 15 | if s[0]-b-c+1 >= 0 then 16 | next_status << [s[0]-b-c+1, s[1]+c, s[2]+b-1, s[3]+1] 17 | end 18 | end 19 | #先生なし 20 | if s[0]-b-c >= 0 then 21 | next_status << [s[0]-b-c, s[1]+c, s[2]+b, s[3]] 22 | end 23 | # 先生から生徒あり 24 | if s[0]-b-c-1 >= 0 then 25 | next_status << [s[0]-b-c-1, s[1]+c+1, s[2]+b, s[3]+1] 26 | end 27 | } 28 | } 29 | } 30 | status = (next_status - status).uniq 31 | step += 1 32 | end 33 | # 経過時間を表示 34 | puts step 35 | # 最短の中で、先生が電話する回数が最少のものを表示 36 | p status.select{|s| s[1] == n}.min{|a, b| a[3] <=> b[3]} 37 | -------------------------------------------------------------------------------- /zh_CN/q14_02.rb: -------------------------------------------------------------------------------- 1 | # 设置一个保持世界杯参赛国的数组 2 | country = ["Brazil", "Croatia", "Mexico", "Cameroon", 3 | "Spain", "Netherlands", "Chile", "Australia", 4 | "Colombia", "Greece", "Cote d'Ivoire", "Japan", 5 | "Uruguay", "Costa Rica", "England", "Italy", 6 | "Switzerland", "Ecuador", "France", "Honduras", 7 | "Argentina", "Bosnia and Herzegovina", "Iran", 8 | "Nigeria", "Germany", "Portugal", "Ghana", 9 | "USA", "Belgium", "Algeria", "Russia", 10 | "Korea Republic"] 11 | def search(countrys, prev, depth) 12 | # 取得所有后续可能的国名 13 | next_country = countrys.select{|c| c[0] == prev[-1].upcase} 14 | if next_country.size > 0 then 15 | # 如果有可用的国名,则加入队列,并除去这个国名继续递归搜索 16 | next_country.each{|c| 17 | search(countrys - [c], c, depth + 1) 18 | } 19 | else 20 | # 如果没有可用国名,则判断当前深度是否最大 21 | @max_depth = [@max_depth, depth].max 22 | end 23 | end 24 | 25 | # 从各个国家开始 26 | @max_depth = 0 27 | country.each{|c| 28 | search(country - [c], c, 1) 29 | } 30 | # 输出最大深度(即连续的国名数目) 31 | puts @max_depth 32 | -------------------------------------------------------------------------------- /zh_CN/q49_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 6, 5 # 横向和纵向的方格数目 2 | USABLE = 2 # 同一条直线可以使用的次数 3 | @max = 0 # 最长距离 4 | @h = Array.new(H + 1, 0) # 保存水平方向线的使用次数 5 | @v = Array.new(W + 1, 0) # 保存垂直方向线的使用次数 6 | 7 | def search(x, y) 8 | if (x == W) && (y == H) then # 如果到达了B点,则确认最大值,终止搜索 9 | @max = [@h.inject(:+) + @v.inject(:+), @max].max 10 | return 11 | end 12 | if @h[y] < USABLE then # 可以水平方向移动的时候 13 | if x > 0 then # 向左移动 14 | @h[y] += 1 15 | search(x - 1, y) 16 | @h[y] -= 1 17 | end 18 | if x < W then # 向右移动 19 | @h[y] += 1 20 | search(x + 1, y) 21 | @h[y] -= 1 22 | end 23 | end 24 | if @v[x] < USABLE then # 可以垂直方向移动的时候 25 | if y > 0 then # 向上移动 26 | @v[x] += 1 27 | search(x, y - 1) 28 | @v[x] -= 1 29 | end 30 | if y < H then # 向下移动 31 | @v[x] += 1 32 | search(x, y + 1) 33 | @v[x] -= 1 34 | end 35 | end 36 | end 37 | 38 | search(0, 0) # 从A位置开始 39 | puts @max 40 | -------------------------------------------------------------------------------- /ja_JP/q14_02.rb: -------------------------------------------------------------------------------- 1 | # ワールドカップ出場国を配列にセット 2 | country = ["Brazil", "Croatia", "Mexico", "Cameroon", 3 | "Spain", "Netherlands", "Chile", "Australia", 4 | "Colombia", "Greece", "Cote d'Ivoire", "Japan", 5 | "Uruguay", "Costa Rica", "England", "Italy", 6 | "Switzerland", "Ecuador", "France", "Honduras", 7 | "Argentina", "Bosnia and Herzegovina", "Iran", 8 | "Nigeria", "Germany", "Portugal", "Ghana", 9 | "USA", "Belgium", "Algeria", "Russia", 10 | "Korea Republic"] 11 | def search(countrys, prev, depth) 12 | # 前の国名に続く国の一覧を取得 13 | next_country = countrys.select{|c| c[0] == prev[-1].upcase} 14 | if next_country.size > 0 then 15 | # 続く国がある場合、その国を除いて再帰的に探索 16 | next_country.each{|c| 17 | search(countrys - [c], c, depth + 1) 18 | } 19 | else 20 | # 続く国がない場合、深さが最大かどうかチェック 21 | @max_depth = [@max_depth, depth].max 22 | end 23 | end 24 | 25 | # すべての国から開始 26 | @max_depth = 0 27 | country.each{|c| 28 | search(country - [c], c, 1) 29 | } 30 | # 深さの最大値(しりとりで続く国の数)を表示 31 | puts @max_depth 32 | -------------------------------------------------------------------------------- /ja_JP/q50_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 6, 5 # 横と縦のマスの数 2 | USABLE = 2 # 使用可能な回数 3 | @max = 0 # 最長の長さ 4 | @h = Array.new(H + 1, 0) # 水平方向の線を使用した回数を保持 5 | @v = Array.new(W + 1, 0) # 垂直方向の線を使用した回数を保持 6 | 7 | def search(x, y) 8 | if (x == W) && (y == H) then # Bについたら最大値を確認して終了 9 | @max = [@h.inject(:+) + @v.inject(:+), @max].max 10 | return 11 | end 12 | if @h[y] < USABLE then # 水平方向に移動可能なとき 13 | if x > 0 then # 左に移動 14 | @h[y] += 1 15 | search(x - 1, y) 16 | @h[y] -= 1 17 | end 18 | if x < W then # 右に移動 19 | @h[y] += 1 20 | search(x + 1, y) 21 | @h[y] -= 1 22 | end 23 | end 24 | if @v[x] < USABLE then # 垂直方向に移動可能なとき 25 | if y > 0 then # 上に移動 26 | @v[x] += 1 27 | search(x, y - 1) 28 | @v[x] -= 1 29 | end 30 | if y < H then # 下に移動 31 | @v[x] += 1 32 | search(x, y + 1) 33 | @v[x] -= 1 34 | end 35 | end 36 | end 37 | 38 | search(0, 0) # Aの位置からスタート 39 | puts @max 40 | -------------------------------------------------------------------------------- /ja_JP/q63_02.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | WEEKS, DAYS = 6, 7 3 | 4 | # 祝日ファイルの読み込み 5 | @holiday = IO.readlines("q63.txt").map{|h| 6 | h.split('/').map(&:to_i) 7 | } 8 | 9 | # カレンダーを満たす最大長方形の面積を算出 10 | def max_rectangle(cal) 11 | s = 0 12 | WEEKS.times{|row| 13 | DAYS.times{|left| 14 | (left..(DAYS - 1)).each{|right| 15 | # 高さを算出 16 | h = (left..right).map{|w| cal[w + row * DAYS]} 17 | # 高さの最小値と横幅で面積を算出 18 | s = [s, h.min * (right - left + 1)].max 19 | } 20 | } 21 | } 22 | s 23 | end 24 | 25 | # 年月を指定し、面積を取得する 26 | def calc(y, m) 27 | cal = Array.new(WEEKS * DAYS, 0) 28 | first = wday = Date.new(y, m, 1).wday # 1日の曜日を取得 29 | Date.new(y, m, -1).day.times{|d| # その月の日の数だけ繰り返し 30 | if 1 <= wday && wday <= 5 && !@holiday.include?([y, m, d + 1]) 31 | # 上にいくつ平日が続いているか? 32 | cal[first + d] = cal[first + d - DAYS] + 1 33 | end 34 | wday = (wday + 1) % DAYS 35 | } 36 | max_rectangle(cal) 37 | end 38 | 39 | yyyymm = [*2006..2015].product([*1..12]) 40 | puts yyyymm.map{|y ,m| calc(y, m)}.inject(:+) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 绝云 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ja_JP/q37_04.js: -------------------------------------------------------------------------------- 1 | function next_dice(dice){ 2 | var top = parseInt(dice / Math.pow(6, 5)); 3 | var left = parseInt(dice / Math.pow(6, 5 - top)); 4 | var right = dice % Math.pow(6, 5 - top); 5 | return (right + 1) * Math.pow(6, top + 1) - (left + 1); 6 | } 7 | 8 | var all_dice = new Array(Math.pow(6, 6)); 9 | for (i = 0; i < Math.pow(6, 6); i++){ 10 | all_dice[i] = 0; 11 | } 12 | for (i = 0; i < Math.pow(6, 6); i++){ 13 | if (all_dice[i] == 0){ 14 | check = new Array(); 15 | while ((all_dice[i] == 0) && (check.indexOf(i) == -1)){ 16 | check.push(i); 17 | i = next_dice(i); 18 | } 19 | index = check.indexOf(i); 20 | if (index >= 0){ 21 | for (j = 0; j < check.length; j++){ 22 | if (j < index){ 23 | all_dice[check[j]] = 1; 24 | } else { 25 | all_dice[check[j]] = 2; 26 | } 27 | } 28 | } else { 29 | for (j = 0; j < check.length; j++){ 30 | all_dice[check[j]] = 1; 31 | } 32 | } 33 | } 34 | } 35 | cnt = 0; 36 | for (i = 0; i < Math.pow(6, 6); i++){ 37 | if (all_dice[i] == 1) cnt++; 38 | } 39 | console.log(cnt); 40 | -------------------------------------------------------------------------------- /zh_CN/q36_04.js: -------------------------------------------------------------------------------- 1 | function next_dice(dice){ 2 | var top = parseInt(dice / Math.pow(6, 5)); 3 | var left = parseInt(dice / Math.pow(6, 5 - top)); 4 | var right = dice % Math.pow(6, 5 - top); 5 | return (right + 1) * Math.pow(6, top + 1) - (left + 1); 6 | } 7 | 8 | var all_dice = new Array(Math.pow(6, 6)); 9 | for (i = 0; i < Math.pow(6, 6); i++){ 10 | all_dice[i] = 0; 11 | } 12 | for (i = 0; i < Math.pow(6, 6); i++){ 13 | if (all_dice[i] == 0){ 14 | check = new Array(); 15 | while ((all_dice[i] == 0) && (check.indexOf(i) == -1)){ 16 | check.push(i); 17 | i = next_dice(i); 18 | } 19 | index = check.indexOf(i); 20 | if (index >= 0){ 21 | for (j = 0; j < check.length; j++){ 22 | if (j < index){ 23 | all_dice[check[j]] = 1; 24 | } else { 25 | all_dice[check[j]] = 2; 26 | } 27 | } 28 | } else { 29 | for (j = 0; j < check.length; j++){ 30 | all_dice[check[j]] = 1; 31 | } 32 | } 33 | } 34 | } 35 | cnt = 0; 36 | for (i = 0; i < Math.pow(6, 6); i++){ 37 | if (all_dice[i] == 1) cnt++; 38 | } 39 | console.log(cnt); 40 | -------------------------------------------------------------------------------- /ja_JP/q30_03.js: -------------------------------------------------------------------------------- 1 | const N = 20; 2 | var memo = []; 3 | memo[1] = 1; 4 | 5 | function set_tap(remain){ 6 | if (memo[remain]){ 7 | return memo[remain]; 8 | } 9 | var cnt = 0; 10 | /* 2口 */ 11 | for (var i = 1; i <= remain / 2; i++){ 12 | if (remain - i == i) 13 | cnt += set_tap(i) * (set_tap(i) + 1) / 2; 14 | else 15 | cnt += set_tap(remain - i) * set_tap(i); 16 | } 17 | /* 3口 */ 18 | for (var i = 1; i <= remain / 3; i++){ 19 | for (var j = i; j <= (remain - i) / 2; j++){ 20 | if ((remain - (i + j) == i) && (i == j)) 21 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6; 22 | else if (remain - (i + j) == i) 23 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2; 24 | else if (i == j) 25 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2; 26 | else if (remain - (i + j) == j) 27 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2; 28 | else 29 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i); 30 | } 31 | } 32 | memo[remain] = cnt; 33 | return cnt; 34 | } 35 | 36 | console.log(set_tap(N)); 37 | -------------------------------------------------------------------------------- /zh_CN/q30_03.js: -------------------------------------------------------------------------------- 1 | const N = 20; 2 | var memo = []; 3 | memo[1] = 1; 4 | 5 | function set_tap(remain){ 6 | if (memo[remain]){ 7 | return memo[remain]; 8 | } 9 | var cnt = 0; 10 | /* 2插口 */ 11 | for (var i = 1; i <= remain / 2; i++){ 12 | if (remain - i == i) 13 | cnt += set_tap(i) * (set_tap(i) + 1) / 2; 14 | else 15 | cnt += set_tap(remain - i) * set_tap(i); 16 | } 17 | /* 3插口 */ 18 | for (var i = 1; i <= remain / 3; i++){ 19 | for (var j = i; j <= (remain - i) / 2; j++){ 20 | if ((remain - (i + j) == i) && (i == j)) 21 | cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6; 22 | else if (remain - (i + j) == i) 23 | cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2; 24 | else if (i == j) 25 | cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2; 26 | else if (remain - (i + j) == j) 27 | cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2; 28 | else 29 | cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i); 30 | } 31 | } 32 | memo[remain] = cnt; 33 | return cnt; 34 | } 35 | 36 | console.log(set_tap(N)); 37 | -------------------------------------------------------------------------------- /zh_CN/q27_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 6, 4 2 | DIR = [[0, 1], [-1, 0], [0, -1], [1, 0]] # 前进方向 3 | left = [0] * H # 用二进制表示某根竖线是否已通过 4 | bottom = [0] * W # 用二进制表示某根横线是否已通过 5 | 6 | def search(x, y, dir, left, bottom) 7 | left_l = left.clone 8 | bottom_l = bottom.clone 9 | # 已经越界或者已通过的情况下无法前行 10 | if (dir == 0) || (dir == 2) then # 前后移动的情况 11 | pos = [y, y + DIR[dir][1]].min 12 | return 0 if (pos < 0) || (y + DIR[dir][1] > H) 13 | return 0 if left_l[pos] & (1 << x) > 0 14 | left_l[pos] |= (1 << x) # 把竖线标记为已通过 15 | else # 左右移动的情况 16 | pos = [x, x + DIR[dir][0]].min 17 | return 0 if (pos < 0) || (x + DIR[dir][0] > W) 18 | return 0 if bottom_l[pos] & (1 << y) > 0 19 | bottom_l[pos] |= (1 << y) # 把横线标记为已通过 20 | end 21 | next_x, next_y = x + DIR[dir][0], y + DIR[dir][1] 22 | return 1 if (next_x == W) && (next_y == H) # 到达B点则结束 23 | 24 | cnt = 0 25 | # 前进 26 | cnt += search(next_x, next_y, dir, left_l, bottom_l) 27 | # 左转 28 | dir = (dir + 1) % DIR.size 29 | cnt += search(next_x, next_y, dir, left_l, bottom_l) 30 | cnt 31 | end 32 | 33 | puts search(0, 0, 3, left, bottom) # 从起点右转开始 34 | -------------------------------------------------------------------------------- /ja_JP/q27_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 6, 4 2 | DIR = [[0, 1], [-1, 0], [0, -1], [1, 0]] # 移動方向 3 | left = [0] * H # 縦の線を使用したかビット単位で保管 4 | bottom = [0] * W # 横の線を使用したかビット単位で保管 5 | 6 | def search(x, y, dir, left, bottom) 7 | left_l = left.clone 8 | bottom_l = bottom.clone 9 | # 境界を越えた場合、または使用済みの場合は進めない 10 | if (dir == 0) || (dir == 2) then # 上下に移動した場合 11 | pos = [y, y + DIR[dir][1]].min 12 | return 0 if (pos < 0) || (y + DIR[dir][1] > H) 13 | return 0 if left_l[pos] & (1 << x) > 0 14 | left_l[pos] |= (1 << x) # 縦の線を使用済みにする 15 | else # 左右に移動した場合 16 | pos = [x, x + DIR[dir][0]].min 17 | return 0 if (pos < 0) || (x + DIR[dir][0] > W) 18 | return 0 if bottom_l[pos] & (1 << y) > 0 19 | bottom_l[pos] |= (1 << y) # 横の線を使用済みにする 20 | end 21 | next_x, next_y = x + DIR[dir][0], y + DIR[dir][1] 22 | return 1 if (next_x == W) && (next_y == H) # Bについたら終了 23 | 24 | cnt = 0 25 | # 直進 26 | cnt += search(next_x, next_y, dir, left_l, bottom_l) 27 | # 左折 28 | dir = (dir + 1) % DIR.size 29 | cnt += search(next_x, next_y, dir, left_l, bottom_l) 30 | cnt 31 | end 32 | 33 | puts search(0, 0, 3, left, bottom) # 始点から右へスタート 34 | -------------------------------------------------------------------------------- /ja_JP/q70_02.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define W 4 4 | #define H 6 5 | 6 | char memo[1 << (W * H)] = {0}; 7 | int queue[1 << (W * H)] = {0x000fff, 0xfff000, 0xcccccc, 0x333333}; 8 | int mask[W * (H - 1) + (W - 1) * H]; 9 | int i, j, mask_count, start, end, temp, depth; 10 | 11 | int main(int argc, char *argv){ 12 | depth = 1; 13 | for (i = 0; i < 4; i++){ 14 | memo[queue[i]] = depth; 15 | } 16 | mask_count = 0; 17 | for (i = 0; i < W * H; i++){ 18 | if (i % W < W - 1) mask[mask_count++] = (1 << 1 | 1) << i; 19 | if (i < W * (H - 1)) mask[mask_count++] = (1 << W | 1) << i; 20 | } 21 | start = 0; 22 | end = temp = 4; 23 | while (end - start > 0){ 24 | printf("%d %d\n", depth - 1, end - start); 25 | depth++; 26 | for (i = start; i < end; i++){ 27 | for (j = 0; j < mask_count; j++){ 28 | if (((queue[i] & mask[j]) != 0) && 29 | ((queue[i] & mask[j]) != mask[j]) && 30 | (memo[queue[i] ^ mask[j]] == 0)){ 31 | memo[queue[i] ^ mask[j]] = depth; 32 | queue[temp++] = queue[i] ^ mask[j]; 33 | } 34 | } 35 | } 36 | start = end; 37 | end = temp; 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /zh_CN/q69_02.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define W 4 4 | #define H 6 5 | 6 | char memo[1 << (W * H)] = {0}; 7 | int queue[1 << (W * H)] = {0x000fff, 0xfff000, 0xcccccc, 0x333333}; 8 | int mask[W * (H - 1) + (W - 1) * H]; 9 | int i, j, mask_count, start, end, temp, depth; 10 | 11 | int main(int argc, char *argv){ 12 | depth = 1; 13 | for (i = 0; i < 4; i++){ 14 | memo[queue[i]] = depth; 15 | } 16 | mask_count = 0; 17 | for (i = 0; i < W * H; i++){ 18 | if (i % W < W - 1) mask[mask_count++] = (1 << 1 | 1) << i; 19 | if (i < W * (H - 1)) mask[mask_count++] = (1 << W | 1) << i; 20 | } 21 | start = 0; 22 | end = temp = 4; 23 | while (end - start > 0){ 24 | printf("%d %d\n", depth - 1, end - start); 25 | depth++; 26 | for (i = start; i < end; i++){ 27 | for (j = 0; j < mask_count; j++){ 28 | if (((queue[i] & mask[j]) != 0) && 29 | ((queue[i] & mask[j]) != mask[j]) && 30 | (memo[queue[i] ^ mask[j]] == 0)){ 31 | memo[queue[i] ^ mask[j]] = depth; 32 | queue[temp++] = queue[i] ^ mask[j]; 33 | } 34 | } 35 | } 36 | start = end; 37 | end = temp; 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /zh_CN/q14_01.rb: -------------------------------------------------------------------------------- 1 | # 设置一个保持世界杯参赛国的数组 2 | @country = ["Brazil", "Croatia", "Mexico", "Cameroon", 3 | "Spain", "Netherlands", "Chile", "Australia", 4 | "Colombia", "Greece", "Cote d'Ivoire", "Japan", 5 | "Uruguay", "Costa Rica", "England", "Italy", 6 | "Switzerland", "Ecuador", "France", "Honduras", 7 | "Argentina", "Bosnia and Herzegovina", "Iran", 8 | "Nigeria", "Germany", "Portugal", "Ghana", 9 | "USA", "Belgium", "Algeria", "Russia", 10 | "Korea Republic"] 11 | # 是否使用过的标记数组 12 | @is_used = Array.new(@country.size, false) 13 | 14 | def search(prev, depth) 15 | is_last = true 16 | @country.each_with_index{|c, i| 17 | if c[0] == prev[-1].upcase then 18 | if !@is_used[i] then 19 | is_last = false 20 | @is_used[i] = true 21 | search(c, depth + 1) 22 | @is_used[i] = false 23 | end 24 | end 25 | } 26 | @max_depth = [@max_depth, depth].max if is_last 27 | end 28 | 29 | # 从各个国家开始 30 | @max_depth = 0 31 | @country.each_with_index{|c, i| 32 | @is_used[i] = true 33 | search(c, 1) 34 | @is_used[i] = false 35 | } 36 | # 输出最大深度(即连续的国名数目) 37 | puts @max_depth 38 | -------------------------------------------------------------------------------- /ja_JP/q14_01.rb: -------------------------------------------------------------------------------- 1 | # ワールドカップ出場国を配列にセット 2 | @country = ["Brazil", "Croatia", "Mexico", "Cameroon", 3 | "Spain", "Netherlands", "Chile", "Australia", 4 | "Colombia", "Greece", "Cote d'Ivoire", "Japan", 5 | "Uruguay", "Costa Rica", "England", "Italy", 6 | "Switzerland", "Ecuador", "France", "Honduras", 7 | "Argentina", "Bosnia and Herzegovina", "Iran", 8 | "Nigeria", "Germany", "Portugal", "Ghana", 9 | "USA", "Belgium", "Algeria", "Russia", 10 | "Korea Republic"] 11 | # 使用済みかをチェック 12 | @is_used = Array.new(@country.size, false) 13 | 14 | def search(prev, depth) 15 | is_last = true 16 | @country.each_with_index{|c, i| 17 | if c[0] == prev[-1].upcase then 18 | if !@is_used[i] then 19 | is_last = false 20 | @is_used[i] = true 21 | search(c, depth + 1) 22 | @is_used[i] = false 23 | end 24 | end 25 | } 26 | @max_depth = [@max_depth, depth].max if is_last 27 | end 28 | 29 | # すべての国から開始 30 | @max_depth = 0 31 | @country.each_with_index{|c, i| 32 | @is_used[i] = true 33 | search(c, 1) 34 | @is_used[i] = false 35 | } 36 | # 深さの最大値(しりとりで続く国の数)を表示 37 | puts @max_depth 38 | -------------------------------------------------------------------------------- /zh_CN/q49_02.js: -------------------------------------------------------------------------------- 1 | const W = 6; /* 横向的方格数目 */ 2 | const H = 5; /* 纵向的方格数目 */ 3 | const USABLE = 2; /* 同一条直线可以使用的次数 */ 4 | var max = 0; /* 最长距离 */ 5 | var h = new Array(H + 1); /* 保存水平方向线的使用次数 */ 6 | var v = new Array(W + 1); /* 保存垂直方向线的使用次数 */ 7 | 8 | for (var i = 0; i < H + 1; i++){ h[i] = 0; } 9 | for (var i = 0; i < W + 1; i++){ v[i] = 0; } 10 | 11 | function sum(a) { 12 | return a.reduce(function(x, y) { return x + y; }); 13 | } 14 | 15 | function search(x, y){ 16 | if ((x == W) && (y == H)){ 17 | /* 如果到达了B点,则确认最大值,终止搜索 */ 18 | max = Math.max(sum(h) + sum(v), max); 19 | return; 20 | } 21 | if (h[y] < USABLE){ /* 可以水平方向移动的时候 */ 22 | if (x > 0) { /* 向左移动 */ 23 | h[y] += 1; 24 | search(x - 1, y); 25 | h[y] -= 1; 26 | } 27 | if (x < W) { /* 向右移动 */ 28 | h[y] += 1; 29 | search(x + 1, y); 30 | h[y] -= 1; 31 | } 32 | } 33 | if (v[x] < USABLE){ /* 可以垂直方向移动的时候 */ 34 | if (y > 0){ /* 向上移动 */ 35 | v[x] += 1; 36 | search(x, y - 1); 37 | v[x] -= 1; 38 | } 39 | if (y < H){ /* 向下移动 */ 40 | v[x] += 1; 41 | search(x, y + 1); 42 | v[x] -= 1; 43 | } 44 | } 45 | } 46 | 47 | search(0, 0); /* 从A位置开始 */ 48 | console.log(max); 49 | -------------------------------------------------------------------------------- /ja_JP/q50_02.js: -------------------------------------------------------------------------------- 1 | const W = 6; /* 横のマスの数 */ 2 | const H = 5; /* 縦のマスの数 */ 3 | const USABLE = 2; /* 使用可能な回数 */ 4 | var max = 0; /* 最長の長さ */ 5 | var h = new Array(H + 1); /* 水平方向の線を使用した回数を保持 */ 6 | var v = new Array(W + 1); /* 垂直方向の線を使用した回数を保持 */ 7 | 8 | for (var i = 0; i < H + 1; i++){ h[i] = 0; } 9 | for (var i = 0; i < W + 1; i++){ v[i] = 0; } 10 | 11 | function sum(a) { 12 | return a.reduce(function(x, y) { return x + y; }); 13 | } 14 | 15 | function search(x, y){ 16 | if ((x == W) && (y == H)){ 17 | /* Bについたら最大値を確認して終了 */ 18 | max = Math.max(sum(h) + sum(v), max); 19 | return; 20 | } 21 | if (h[y] < USABLE){ /* 水平方向に移動可能なとき */ 22 | if (x > 0) { /* 左に移動 */ 23 | h[y] += 1; 24 | search(x - 1, y); 25 | h[y] -= 1; 26 | } 27 | if (x < W) { /* 右に移動 */ 28 | h[y] += 1; 29 | search(x + 1, y); 30 | h[y] -= 1; 31 | } 32 | } 33 | if (v[x] < USABLE){ /* 垂直方向に移動可能なとき */ 34 | if (y > 0){ /* 上に移動 */ 35 | v[x] += 1; 36 | search(x, y - 1); 37 | v[x] -= 1; 38 | } 39 | if (y < H){ /* 下に移動 */ 40 | v[x] += 1; 41 | search(x, y + 1); 42 | v[x] -= 1; 43 | } 44 | } 45 | } 46 | 47 | search(0, 0); /* Aの位置からスタート */ 48 | console.log(max); 49 | -------------------------------------------------------------------------------- /zh_CN/q62_02.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | WEEKS, DAYS = 6, 7 3 | 4 | # 读入假日数据文件 5 | @holiday = IO.readlines("q62-holiday.txt").map{|h| 6 | h.split('/').map(&:to_i) 7 | } 8 | # 读入调休工作日数据文件 9 | @extra_workday = IO.readlines("q62-extra-workday.txt").map{|h| 10 | h.split('/').map(&:to_i) 11 | } 12 | 13 | # 计算符合条件的最大长方形的面积 14 | def max_rectangle(cal) 15 | s = 0 16 | WEEKS.times{|row| 17 | DAYS.times{|left| 18 | (left..(DAYS - 1)).each{|right| 19 | # 计算高度 20 | h = (left..right).map{|w| cal[w + row * DAYS]} 21 | # 通过高度的最小值和横向长度计算面积 22 | s = [s, h.min * (right - left + 1)].max 23 | } 24 | } 25 | } 26 | s 27 | end 28 | 29 | # 指定年份月份,获取最大长方形面积 30 | def calc(y, m) 31 | cal = Array.new(WEEKS * DAYS, 0) 32 | first = wday = Date.new(y, m, 1).wday # 获取该月1日的星期 33 | Date.new(y, m, -1).day.times{|d| # 循环处理直到该月结束 34 | if (1 <= wday && wday <= 5 && !@holiday.include?([y, m, d + 1])) || @extra_workday.include?([y, m, d + 1]) 35 | # 纵向工作日延续几行? 36 | cal[first + d] = cal[first + d - DAYS] + 1 37 | end 38 | wday = (wday + 1) % DAYS 39 | } 40 | max_rectangle(cal) 41 | end 42 | 43 | yyyymm = [*2006..2015].product([*1..12]) 44 | puts yyyymm.map{|y ,m| calc(y, m)}.inject(:+) 45 | -------------------------------------------------------------------------------- /zh_CN/q61_02.rb: -------------------------------------------------------------------------------- 1 | # 设置方格点数目 2 | W, H = 5, 4 3 | # 移动方向 4 | @move = [[0, 1], [0, -1], [1, 0], [-1, 0]] 5 | @log = {} 6 | 7 | # 递归遍历 8 | def search(x, y, depth) 9 | return 0 if x < 0 || W <= x || y < 0 || H <= y 10 | return 0 if @log.has_key?(x + y * W) 11 | return 1 if depth == W * H 12 | # 遍历到一半,检查剩下的点是否连结 13 | if depth == W * H / 2 then 14 | remain = (0..(W*H-1)).to_a - @log.keys 15 | check(remain, remain[0]) 16 | return 0 if remain.size > 0 17 | end 18 | cnt = 0 19 | @log[x + y * W] = depth 20 | @move.each{|m| # 上下左右移动 21 | cnt += search(x + m[0], y + m[1], depth + 1) 22 | } 23 | @log.delete(x + y * W) 24 | return cnt 25 | end 26 | 27 | # 检查是否连结 28 | def check(remain, del) 29 | remain.delete(del) 30 | left, right, up, down = del - 1, del + 1, del - W, del + W 31 | # 如果前方是同色的,则检索 32 | check(remain, left) if (del % W > 0) && remain.include?(left) 33 | check(remain, right) if (del % W != W - 1) && remain.include?(right) 34 | check(remain, up) if (del / W > 0) && remain.include?(up) 35 | check(remain, down) if (del / W != H - 1) && remain.include?(down) 36 | end 37 | 38 | count = 0 39 | (W * H).times{|i| 40 | count += search(i % W, i / W, 1) 41 | } 42 | 43 | # 起点终点互换位置得到的路径和原先一致,所以最终数目减半 44 | puts count / 2 45 | -------------------------------------------------------------------------------- /zh_CN/q64_02.rb: -------------------------------------------------------------------------------- 1 | # 6组对手 2 | PAIR = 6 3 | 4 | # 设置起始和终止状态 5 | start = (1..PAIR * 2 - 1).to_a + [0] 6 | goal = [0] + (2..PAIR * 2 - 1).to_a + [1] 7 | 8 | # 获取投接球状态列表 9 | def throwable(balls) 10 | result = [] 11 | balls.each{|ball| 12 | c = ball.index(0) # 获取接球手位置 13 | p = (c + PAIR) % (PAIR * 2) # 计算接球手对面位置 14 | [-1, 0, 1].each{|d| # 正对面及其左右 15 | if (p + d) / PAIR == p / PAIR then 16 | ball[c], ball[p + d] = ball[p + d], ball[c] 17 | result.push(ball.clone) # 设置投球结果 18 | ball[c], ball[p + d] = ball[p + d], ball[c] 19 | end 20 | } 21 | } 22 | result 23 | end 24 | 25 | # 设定初始状态 26 | fw = [start] 27 | fw_log = [start] 28 | bw = [goal] 29 | bw_log = [goal] 30 | cnt = 0 31 | 32 | # 双向的广度优先搜索 33 | while true do 34 | next_fw = throwable(fw) # 正向的下一步 35 | fw = next_fw - fw_log # 选择之前没有出现过的投球方案 36 | fw_log |= next_fw # 添加投球结果 37 | cnt += 1 38 | break if (fw & bw).size > 0 # 如果状态相同,则终止处理 39 | 40 | next_bw = throwable(bw) # 反向的下一步 41 | bw = next_bw - bw_log # 选择之前没有出现过的投球方案 42 | bw_log |= next_bw # 添加投球结果 43 | cnt += 1 44 | break if (fw & bw).size > 0 # 如果状态相同,则终止处理 45 | end 46 | puts cnt 47 | -------------------------------------------------------------------------------- /ja_JP/q67_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 6, 5 2 | # マス目の初期化 3 | @puzzle = Array.new(W + 2).map{Array.new(H + 2, 0)} 4 | (W+2).times{|w| 5 | (H+2).times{|h| 6 | if (w==0) || (w==W+1) || (h==0) || (h==H + 1) then 7 | @puzzle[w][h] = -1 8 | end 9 | } 10 | } 11 | 12 | def fill(x, y, from, to) # 連続チェック用に埋めていく 13 | if @puzzle[x][y] == from then 14 | @puzzle[x][y] = to 15 | fill(x - 1, y, from, to) 16 | fill(x + 1, y, from, to) 17 | fill(x, y - 1, from, to) 18 | fill(x, y + 1, from, to) 19 | end 20 | end 21 | 22 | def check() 23 | x, y = 1, 1 24 | x += 1 if @puzzle[x][y] == 1 25 | fill(x, y, 0, 2) # 白マスをダミーで埋める 26 | result = (@puzzle.flatten.count(0) == 0) 27 | fill(x, y, 2, 0) # ダミーを白マスに戻す 28 | result 29 | end 30 | 31 | def search(x, y) 32 | x, y = 1, y + 1 if x == W + 1 # 右端に到達したら次の行 33 | return 1 if y == H + 1 # 最後まで探索できれば成功 34 | cnt = search(x + 1, y) # 白マスをセットして次を探索 35 | # 左か上が黒マス以外の場合、黒マスをセットして次を探索 36 | if (@puzzle[x - 1][y] != 1) && (@puzzle[x][y - 1] != 1) then 37 | @puzzle[x][y] = 1 # 黒マスをセット 38 | cnt += search(x + 1, y) if check() 39 | @puzzle[x][y] = 0 # 黒マスを戻す 40 | end 41 | cnt 42 | end 43 | 44 | p search(1, 1) # 左上から開始 45 | -------------------------------------------------------------------------------- /ja_JP/q65_02.rb: -------------------------------------------------------------------------------- 1 | # ペアは6組 2 | PAIR = 6 3 | 4 | # 開始と終了を設定 5 | start = (1..PAIR * 2 - 1).to_a + [0] 6 | goal = [0] + (2..PAIR * 2 - 1).to_a + [1] 7 | 8 | # 投げられる一覧を取得 9 | def throwable(balls) 10 | result = [] 11 | balls.each{|ball| 12 | c = ball.index(0) # 受け手の位置を取得 13 | p = (c + PAIR) % (PAIR * 2) # 受け手の正面を計算 14 | [-1, 0, 1].each{|d| # 正面と左右 15 | if (p + d) / PAIR == p / PAIR then 16 | ball[c], ball[p + d] = ball[p + d], ball[c] 17 | result.push(ball.clone) # 投げた結果をセット 18 | ball[c], ball[p + d] = ball[p + d], ball[c] 19 | end 20 | } 21 | } 22 | result 23 | end 24 | 25 | # 初期状態を設定 26 | fw = [start] 27 | fw_log = [start] 28 | bw = [goal] 29 | bw_log = [goal] 30 | cnt = 0 31 | 32 | # 双方向からの幅優先探索を実行 33 | while true do 34 | next_fw = throwable(fw) # 順方向に次のステップを取得 35 | fw = next_fw - fw_log # 過去に現れていないものを選択 36 | fw_log |= next_fw # 投げた結果を追加 37 | cnt += 1 38 | break if (fw & bw).size > 0 # 重なったら終了 39 | 40 | next_bw = throwable(bw) # 逆方向に次のステップを取得 41 | bw = next_bw - bw_log # 過去に現れていないものを選択 42 | bw_log |= next_bw # 投げた結果を追加 43 | cnt += 1 44 | break if (fw & bw).size > 0 # 重なったら終了 45 | end 46 | puts cnt 47 | -------------------------------------------------------------------------------- /zh_CN/q29_01.rb: -------------------------------------------------------------------------------- 1 | # 计算数组的直接值 2 | def product(ary) 3 | result = ary[0] 4 | 1.upto(ary.size - 1){|i| 5 | result = result.product(ary[i]) 6 | } 7 | result.map{|r| r.flatten} 8 | end 9 | 10 | # 计算并联时的电阻值 11 | def parallel(ary) 12 | #1.0 / ary.map{|i| 1.0 / i}.inject(:+) 13 | Rational(1, ary.map{|i| Rational(1, i)}.inject(:+)) 14 | end 15 | 16 | @memo = {1 => [1]} 17 | def calc(n) 18 | return @memo[n] if @memo.has_key?(n) 19 | # 串联 20 | result = calc(n - 1).map{|i| i + 1} 21 | # 并联 22 | 2.upto(n){|i| 23 | # 设置并联切分的个数 24 | cut = {} 25 | (1..(n - 1)).to_a.combination(i - 1){|ary| 26 | pos = 0 27 | r = [] 28 | ary.size.times{|j| 29 | r.push(ary[j] - pos) 30 | pos = ary[j] 31 | } 32 | r.push(n - pos) 33 | cut[r.sort] = 1 34 | } 35 | # 递归地设置切分位置 36 | keys = cut.keys.map{|c| 37 | c.map{|e| calc(e)} 38 | } 39 | # 计算电阻值 40 | keys.map{|k| product(k)}.each{|k| 41 | k.each{|vv| result.push(parallel(vv))} 42 | } 43 | } 44 | @memo[n] = result 45 | end 46 | 47 | golden_ratio = 1.61800339887 48 | min = Float::INFINITY 49 | calc(10).each{|i| 50 | min = i if (golden_ratio - i).abs < (golden_ratio - min).abs 51 | } 52 | puts sprintf("%.10f", min) 53 | puts min 54 | -------------------------------------------------------------------------------- /ja_JP/q63_01.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | WEEKS, DAYS = 6, 7 3 | 4 | # 祝日ファイルの読み込み 5 | @holiday = IO.readlines("q63.txt").map{|h| 6 | h.split('/').map(&:to_i) 7 | } 8 | 9 | # カレンダーを満たす最大長方形の面積を算出 10 | def max_rectangle(cal) 11 | rect = 0 12 | WEEKS.times{|sr| # 開始点の行 13 | DAYS.times{|sc| # 開始点の列 14 | sr.upto(WEEKS){|er| # 終了点の行 15 | sc.upto(DAYS){|ec| # 終了点の列 16 | is_weekday = true # 開始点と終了点の内部に平日以外があるか 17 | sr.upto(er){|r| 18 | sc.upto(ec){|c| 19 | is_weekday = false if cal[c + r * DAYS] == 0 20 | } 21 | } 22 | if is_weekday then 23 | rect = [rect, (er - sr + 1) * (ec - sc + 1)].max 24 | end 25 | } 26 | } 27 | } 28 | } 29 | rect 30 | end 31 | 32 | # 年月を指定し、面積を取得する 33 | def calc(y, m) 34 | cal = Array.new(WEEKS * DAYS, 0) 35 | first = wday = Date.new(y, m, 1).wday # 1日の曜日を取得 36 | Date.new(y, m, -1).day.times{|d| # その月の日の数だけ繰り返し 37 | if 1 <= wday && wday <= 5 && !@holiday.include?([y, m, d + 1]) 38 | cal[first + d] = 1 39 | end 40 | wday = (wday + 1) % DAYS 41 | } 42 | max_rectangle(cal) 43 | end 44 | 45 | yyyymm = [*2006..2015].product([*1..12]) 46 | puts yyyymm.map{|y ,m| calc(y, m)}.inject(:+) 47 | -------------------------------------------------------------------------------- /ja_JP/q66_02.rb: -------------------------------------------------------------------------------- 1 | # パネルの数を設定 2 | W, H = 4, 3 3 | row = [0] + [1] * (W - 1) + [0] 4 | @edge = row + row.map{|r| 1 - r} * (H - 1) + row 5 | 6 | def search(panel, odds) 7 | # 最後のパネルをセットしたときに奇数点が2個を超えるか 8 | return (@edge.inject(:+) > 2)?0:1 if panel >= (W + 1) * H 9 | # 途中で奇数点が2個を超えると一筆書き不可 10 | return 0 if odds > 2 11 | 12 | cnt = 0 13 | if panel % (W + 1) < W then # 行の右端以外 14 | # パネル内に斜線がない場合を探索 15 | cnt += search(panel + 1, odds + @edge[panel]) 16 | 17 | # パネルの左上から右下への線 18 | @edge[panel] = 1 - @edge[panel] 19 | @edge[panel + W + 2] = 1 - @edge[panel + W + 2] 20 | cnt += search(panel + 1, odds + @edge[panel]) 21 | 22 | # パネルをクロスする線 23 | @edge[panel + 1] = 1 - @edge[panel + 1] 24 | @edge[panel + W + 1] = 1 - @edge[panel + W + 1] 25 | cnt += search(panel + 1, odds + @edge[panel]) 26 | 27 | # パネルの右上から左下への線 28 | @edge[panel] = 1 - @edge[panel] 29 | @edge[panel + W + 2] = 1 - @edge[panel + W + 2] 30 | cnt += search(panel + 1, odds + @edge[panel]) 31 | 32 | # 斜線を元に戻す 33 | @edge[panel + 1] = 1 - @edge[panel + 1] 34 | @edge[panel + W + 1] = 1 - @edge[panel + W + 1] 35 | else # 行の右端の場合、次の行へ 36 | cnt += search(panel + 1, odds + @edge[panel]) 37 | end 38 | cnt 39 | end 40 | 41 | puts search(0, 0) 42 | -------------------------------------------------------------------------------- /ja_JP/q29_01.rb: -------------------------------------------------------------------------------- 1 | # 配列の直積を計算 2 | def product(ary) 3 | result = ary[0] 4 | 1.upto(ary.size - 1){|i| 5 | result = result.product(ary[i]) 6 | } 7 | result.map{|r| r.flatten} 8 | end 9 | 10 | # 並列の場合の抵抗値を算出 11 | def parallel(ary) 12 | #1.0 / ary.map{|i| 1.0 / i}.inject(:+) 13 | Rational(1, ary.map{|i| Rational(1, i)}.inject(:+)) 14 | end 15 | 16 | @memo = {1 => [1]} 17 | def calc(n) 18 | return @memo[n] if @memo.has_key?(n) 19 | # 直列 20 | result = calc(n - 1).map{|i| i + 1} 21 | # 並列 22 | 2.upto(n){|i| 23 | # 並列で区切る個数を設定 24 | cut = {} 25 | (1..(n - 1)).to_a.combination(i - 1){|ary| 26 | pos = 0 27 | r = [] 28 | ary.size.times{|j| 29 | r.push(ary[j] - pos) 30 | pos = ary[j] 31 | } 32 | r.push(n - pos) 33 | cut[r.sort] = 1 34 | } 35 | # 区切った位置で再帰的に抵抗を設定 36 | keys = cut.keys.map{|c| 37 | c.map{|e| calc(e)} 38 | } 39 | # 抵抗値を計算 40 | keys.map{|k| product(k)}.each{|k| 41 | k.each{|vv| result.push(parallel(vv))} 42 | } 43 | } 44 | @memo[n] = result 45 | end 46 | 47 | golden_ratio = 1.61800339887 48 | min = Float::INFINITY 49 | calc(10).each{|i| 50 | min = i if (golden_ratio - i).abs < (golden_ratio - min).abs 51 | } 52 | puts sprintf("%.10f", min) 53 | puts min 54 | -------------------------------------------------------------------------------- /ja_JP/q62_02.rb: -------------------------------------------------------------------------------- 1 | # 格子点の数を設定 2 | W, H = 5, 4 3 | # 移動する方向 4 | @move = [[0, 1], [0, -1], [1, 0], [-1, 0]] 5 | @log = {} 6 | 7 | # 再帰的に探索する 8 | def search(x, y, depth) 9 | return 0 if x < 0 || W <= x || y < 0 || H <= y 10 | return 0 if @log.has_key?(x + y * W) 11 | return 1 if depth == W * H 12 | # 半分程度まで探索したら、残りが連結されているかチェック 13 | if depth == W * H / 2 then 14 | remain = (0..(W*H-1)).to_a - @log.keys 15 | check(remain, remain[0]) 16 | return 0 if remain.size > 0 17 | end 18 | cnt = 0 19 | @log[x + y * W] = depth 20 | @move.each{|m| # 上下左右に移動 21 | cnt += search(x + m[0], y + m[1], depth + 1) 22 | } 23 | @log.delete(x + y * W) 24 | return cnt 25 | end 26 | 27 | # 連結されているかをチェックする 28 | def check(remain, del) 29 | remain.delete(del) 30 | left, right, up, down = del - 1, del + 1, del - W, del + W 31 | # 移動先に同じ色があればその方向を探索 32 | check(remain, left) if (del % W > 0) && remain.include?(left) 33 | check(remain, right) if (del % W != W - 1) && remain.include?(right) 34 | check(remain, up) if (del / W > 0) && remain.include?(up) 35 | check(remain, down) if (del / W != H - 1) && remain.include?(down) 36 | end 37 | 38 | count = 0 39 | (W * H).times{|i| 40 | count += search(i % W, i / W, 1) 41 | } 42 | 43 | # 始点と終点が逆のパターンは同一とみなすので半分にする 44 | puts count / 2 45 | -------------------------------------------------------------------------------- /ja_JP/q64_01.rb: -------------------------------------------------------------------------------- 1 | N = 5 2 | # 右手法の移動方向(右、上、左、下の順) 3 | @dx = [[1, 0], [0, -1], [-1, 0], [0, 1]] 4 | 5 | # maze:壁の配置 6 | # p1, d1: 1人目の経路、移動方向 7 | # p2, d2: 2人目の経路、移動方向 8 | def search(maze, p1, d1, p2, d2) 9 | if p1.size == p2.size then # 2人がともに移動した場合 10 | # 2人が出会った場合は成功 11 | return true if p1[-1][0..1] == p2[-1][0..1] 12 | # 1人目が右下に着いた場合は失敗 13 | return false if p1[-1][0..1] == [N - 1, N - 1] 14 | # 2人目が左上に着いた場合も失敗 15 | return false if p2[-1][0..1] == [0, 0] 16 | end 17 | # 同じ方向から移動してきた場合はループなので失敗 18 | return false if p1.count(p1[-1]) > 1 19 | 20 | pre = p1[-1] 21 | @dx.size.times{|i| # 右手法で動ける方向を探索 22 | d = (d1 - 1 + i) % @dx.size 23 | px = pre[0] + @dx[d][0] 24 | py = pre[1] + @dx[d][1] 25 | # 移動先が壁になっていないかチェック 26 | if (px >= 0) && (px < N) && (py >= 0) && (py < N) && 27 | (maze[px + N * py] == 0) then 28 | return search(maze, p2, d2, p1 + [[px, py, d]], d) 29 | break 30 | end 31 | } 32 | false 33 | end 34 | 35 | a = [[0, 0, -1]] # A:左上(X座標、Y座標、前の移動方向) 36 | b = [[N - 1, N - 1, -1]] # B:右下(X座標、Y座標、前の移動方向) 37 | cnt = 0 38 | [0, 1].repeated_permutation(N * N - 2){|maze| 39 | # 2人の開始位置は必ず通路として探索 40 | # Aは下に移動(@dx[3])、Bは上に移動(@dx[1]) 41 | cnt += 1 if search([0] + maze + [0], a, 3, b, 1) 42 | } 43 | puts cnt 44 | -------------------------------------------------------------------------------- /zh_CN/q65_02.rb: -------------------------------------------------------------------------------- 1 | # 设置图块数目 2 | W, H = 4, 3 3 | row = [0] + [1] * (W - 1) + [0] 4 | @edge = row + row.map{|r| 1 - r} * (H - 1) + row 5 | 6 | def search(panel, odds) 7 | # 截至最后一个图块,奇数顶点是否超过2个 8 | return (@edge.inject(:+) > 2)?0:1 if panel >= (W + 1) * H 9 | # 途中で奇数点が2個を超えると一筆書き不可 10 | # 如果中途奇数顶点超过2个,则不可能完成一笔画 11 | return 0 if odds > 2 12 | 13 | cnt = 0 14 | if panel % (W + 1) < W then # 到达行的最右侧 15 | # 遍历图块内没有斜线的情况 16 | cnt += search(panel + 1, odds + @edge[panel]) 17 | 18 | # 图块有从左上到右下的线 19 | @edge[panel] = 1 - @edge[panel] 20 | @edge[panel + W + 2] = 1 - @edge[panel + W + 2] 21 | cnt += search(panel + 1, odds + @edge[panel]) 22 | 23 | # 图块有交叉线 24 | @edge[panel + 1] = 1 - @edge[panel + 1] 25 | @edge[panel + W + 1] = 1 - @edge[panel + W + 1] 26 | cnt += search(panel + 1, odds + @edge[panel]) 27 | 28 | # 图块有从右上到左下的线 29 | @edge[panel] = 1 - @edge[panel] 30 | @edge[panel + W + 2] = 1 - @edge[panel + W + 2] 31 | cnt += search(panel + 1, odds + @edge[panel]) 32 | 33 | # 斜线回到原点 34 | @edge[panel + 1] = 1 - @edge[panel + 1] 35 | @edge[panel + W + 1] = 1 - @edge[panel + W + 1] 36 | else # 到达行右端时,进入下一行 37 | cnt += search(panel + 1, odds + @edge[panel]) 38 | end 39 | cnt 40 | end 41 | 42 | puts search(0, 0) 43 | -------------------------------------------------------------------------------- /zh_CN/q37_04.js: -------------------------------------------------------------------------------- 1 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 2 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011]; 3 | 4 | /* 统计比特序列中1的个数 */ 5 | function bitcount(x) { 6 | x = (x & 0x55555555) + (x >> 1 & 0x55555555); 7 | x = (x & 0x33333333) + (x >> 2 & 0x33333333); 8 | x = (x & 0x0F0F0F0F) + (x >> 4 & 0x0F0F0F0F); 9 | x = (x & 0x00FF00FF) + (x >> 8 & 0x00FF00FF); 10 | x = (x & 0x0000FFFF) + (x >> 16 & 0x0000FFFF); 11 | return x; 12 | } 13 | 14 | var flip = new Array(10); 15 | for (i = 0; i < 10; i++){ 16 | flip[i] = new Array(10); 17 | for (j = 0; j < 10; j++){ 18 | flip[i][j] = bitcount(bit[i]^bit[j]); 19 | } 20 | } 21 | 22 | var min = 63; 23 | function search(is_used, sum, prev){ 24 | if (is_used.indexOf(false) == -1){ 25 | min = sum; 26 | } else { 27 | for (var i = 0; i < 10; i++){ 28 | if (!is_used[i]){ 29 | is_used[i] = true; 30 | var next_sum = 0; 31 | if (prev >= 0) 32 | next_sum = sum + flip[prev][i]; 33 | if (min > next_sum) 34 | search(is_used, next_sum, i); 35 | is_used[i] = false; 36 | } 37 | } 38 | } 39 | } 40 | is_used = [false, false, false, false, false, 41 | false, false, false, false, false]; 42 | search(is_used, 0, -1) 43 | console.log(min); 44 | -------------------------------------------------------------------------------- /zh_CN/q59_04.rb: -------------------------------------------------------------------------------- 1 | # 设置搜索的边界 2 | W, H = 4, 4 3 | # 从单元格顶点有没有往上下左右方向的线 4 | # U: 上, D: 下, L: 左, R: 右用比特列设置方向 5 | U, D, L, R = 0b1000, 0b0100, 0b0010, 0b0001 6 | 7 | # 单元格顶点只计算内侧,因此行列减1 8 | @width, @height = W - 1, H - 1 9 | # 设置单元格顶点的可能状态 10 | @dir = [U|D, L|R, U|D|L, U|D|R, U|L|R, D|L|R, U|D|L|R, 0b0] 11 | @row = {} 12 | 13 | # 对每行统计上下连接的组合 14 | def make_row(cell) 15 | if cell.size == @width then # 能组合出1行的时候 16 | u = cell.map{|l| l & U > 0} # 往上连线的位置(T/F) 17 | d = cell.map{|l| l & D > 0} # 往下连线的位置(T/F) 18 | if @row.has_key?(u) then 19 | @row[u][d] = @row[u].fetch(d, 0) + 1 20 | else 21 | @row[u] = {d => 1} 22 | end 23 | return 24 | end 25 | @dir.each{|d| 26 | # 最左侧或者左侧的线和右侧的线重合时 27 | if (cell.size == 0) || 28 | ((d & L > 0) == (cell.last & R > 0)) then 29 | make_row(cell + [d]) 30 | end 31 | } 32 | end 33 | 34 | make_row([]) 35 | 36 | # 统计第1行往下连线的组合数 37 | count = Hash.new(0) 38 | @row.each{|up, down| 39 | down.each{|k, v| count[k] += v } 40 | } 41 | 42 | # 从第2行开始,结合上一行进行统计 43 | h = 1 44 | while h < @height do 45 | new_count = Hash.new(0) 46 | count.each{|bar, cnt| 47 | @row[bar].each{|k, v| new_count[k] += cnt * v } 48 | } 49 | h += 1 50 | count = new_count 51 | end 52 | 53 | p count.inject(0){|sum, (k, v)| sum + v} 54 | -------------------------------------------------------------------------------- /ja_JP/q38_04.js: -------------------------------------------------------------------------------- 1 | bit = [0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 2 | 0b1011011, 0b1011111, 0b1110000, 0b1111111, 0b1111011]; 3 | 4 | /* 1が立っているビットの数を数える */ 5 | function bitcount(x) { 6 | x = (x & 0x55555555) + (x >> 1 & 0x55555555); 7 | x = (x & 0x33333333) + (x >> 2 & 0x33333333); 8 | x = (x & 0x0F0F0F0F) + (x >> 4 & 0x0F0F0F0F); 9 | x = (x & 0x00FF00FF) + (x >> 8 & 0x00FF00FF); 10 | x = (x & 0x0000FFFF) + (x >> 16 & 0x0000FFFF); 11 | return x; 12 | } 13 | 14 | var flip = new Array(10); 15 | for (i = 0; i < 10; i++){ 16 | flip[i] = new Array(10); 17 | for (j = 0; j < 10; j++){ 18 | flip[i][j] = bitcount(bit[i]^bit[j]); 19 | } 20 | } 21 | 22 | var min = 63; 23 | function search(is_used, sum, prev){ 24 | if (is_used.indexOf(false) == -1){ 25 | min = sum; 26 | } else { 27 | for (var i = 0; i < 10; i++){ 28 | if (!is_used[i]){ 29 | is_used[i] = true; 30 | var next_sum = 0; 31 | if (prev >= 0) 32 | next_sum = sum + flip[prev][i]; 33 | if (min > next_sum) 34 | search(is_used, next_sum, i); 35 | is_used[i] = false; 36 | } 37 | } 38 | } 39 | } 40 | is_used = [false, false, false, false, false, 41 | false, false, false, false, false]; 42 | search(is_used, 0, -1) 43 | console.log(min); 44 | -------------------------------------------------------------------------------- /ja_JP/q60_04.rb: -------------------------------------------------------------------------------- 1 | # サイズの設定 2 | W, H = 4, 4 3 | # 格子点から上下左右に線が出ているかどうか 4 | # U: 上, D: 下, L: 左, R: 右 5 | U, D, L, R = 0b1000, 0b0100, 0b0010, 0b0001 6 | 7 | # 格子点の数は内側のため、行と列が1少ない 8 | @width, @height = W - 1, H - 1 9 | # 格子点として可能な形をセット 10 | @dir = [U|D, L|R, U|D|L, U|D|R, U|L|R, D|L|R, U|D|L|R, 0b0] 11 | @row = {} 12 | 13 | # 1行での上下のつながり方を作成 14 | def make_row(cell) 15 | if cell.size == @width then # 1行分を作成できたとき 16 | u = cell.map{|l| l & U > 0} # 上方向に線が出ている位置(T/F) 17 | d = cell.map{|l| l & D > 0} # 下方向に線が出ている位置(T/F) 18 | if @row.has_key?(u) then 19 | @row[u][d] = @row[u].fetch(d, 0) + 1 20 | else 21 | @row[u] = {d => 1} 22 | end 23 | return 24 | end 25 | @dir.each{|d| 26 | # 左端または左隣からの線が右からの線と一致する。 27 | if (cell.size == 0) || 28 | ((d & L > 0) == (cell.last & R > 0)) then 29 | make_row(cell + [d]) 30 | end 31 | } 32 | end 33 | 34 | make_row([]) 35 | 36 | # 最初の行で下に線が出ている件数を合計 37 | count = Hash.new(0) 38 | @row.each{|up, down| 39 | down.each{|k, v| count[k] += v } 40 | } 41 | 42 | # 2行目以降について、前の行とつながる数を合計 43 | h = 1 44 | while h < @height do 45 | new_count = Hash.new(0) 46 | count.each{|bar, cnt| 47 | @row[bar].each{|k, v| new_count[k] += cnt * v } 48 | } 49 | h += 1 50 | count = new_count 51 | end 52 | 53 | p count.inject(0){|sum, (k, v)| sum + v} 54 | -------------------------------------------------------------------------------- /zh_CN/q59_01.rb: -------------------------------------------------------------------------------- 1 | # 设置搜索的边界 2 | W, H = 4, 4 3 | 4 | # 搜索函数 5 | # pos : 搜索位置 6 | # cells : 用true/false表示单元格是否已经被使用 7 | # is1x1 : 是否1×1的单元格 8 | # 返回值 : 合并方式数目和不出现1x1单元格的合并方式数目 9 | def search(pos, cells, is1x1) 10 | if pos == W * H then # 搜索结束 11 | if is1x1 then 12 | return [1, 0] 13 | else 14 | return [1, 1] 15 | end 16 | end 17 | 18 | # 如果搜索位置已被使用,则移动到下一个位置 19 | return search(pos + 1, cells, is1x1) if cells[pos] 20 | 21 | # 按顺序搜索矩形 22 | x, y = pos % W, pos / W 23 | result = [0, 0] 24 | (1..(H - y)).each{|dy| # 垂直方向的边界 25 | (1..(W - x)).each{|dx| # 水平方向的边界 26 | next_cells = cells.clone 27 | settable = true # 能否设置矩形 28 | dy.times{|h| 29 | dx.times{|w| 30 | if next_cells[(x + w) + (y + h) * W] then 31 | # 已经设置完毕 32 | settable = false 33 | else 34 | next_cells[(x + w) + (y + h) * W] = true 35 | end 36 | } 37 | } 38 | if settable then 39 | # 如果能设置长方形,则设置并进入下一次搜索 40 | res = search(pos + 1, next_cells, 41 | is1x1 || (dx == 1 && dy == 1)) 42 | result[0] += res[0] 43 | result[1] += res[1] 44 | end 45 | } 46 | } 47 | return result 48 | end 49 | 50 | # 初始化单元格 51 | cells = Array.new(W * H, false) 52 | puts search(0, cells, false) 53 | -------------------------------------------------------------------------------- /zh_CN/q63_01.rb: -------------------------------------------------------------------------------- 1 | N = 5 2 | # 右手法则的移动方向(按右、上、左、下的顺序) 3 | @dx = [[1, 0], [0, -1], [-1, 0], [0, 1]] 4 | 5 | # maze: 墙壁设置 6 | # p1, d1: 第1个人走过的路径和移动方向 7 | # p2, d2: 第2个人走过的路径和移动方向 8 | def search(maze, p1, d1, p2, d2) 9 | if p1.size == p2.size then # 两人同时移动的情况 10 | # 两人相遇则成功 11 | return true if p1[-1][0..1] == p2[01][0..1] 12 | # 第1个人到达右下方则失败 13 | return false if p1[-1][0..1] == [N - 1, N - 1] 14 | # 第2个人到达左上方则失败 15 | return false if p2[-1][0..1] == [0, 0] 16 | end 17 | # 两人往同一个方向移动则移动方向形成环,失败 18 | return false if p1.count(p1[-1]) > 1 19 | 20 | pre = p1[-1] 21 | @dx.size.times{|i| # 搜索右手法则指定的方向 22 | d = (d1 - 1 + i) % @dx.size 23 | px = pre[0] + @dx[d][0] 24 | py = pre[1] + @dx[d][1] 25 | # 判断移动前方是否是墙壁 26 | if (px >= 0) && (px < N) && (py >= 0) && (py < N) && (maze[px + N * py] == 0) then 27 | return search(maze, p2, d2, p1 + [[px, py, d]], d) 28 | break 29 | end 30 | } 31 | false 32 | end 33 | 34 | a = [[0, 0, -1]] # A: 左上角(X坐标,Y坐标、向前的移动方向) 35 | b = [[N - 1, N - 1, -1]] # B: 右下角(X坐标,Y坐标、向前的移动方向) 36 | cnt = 0 37 | [0, 1].repeated_permutation(N * N - 2){|maze| 38 | # 两人的起始位置一定作为路径的一部分检索 39 | # A向下移动(@dx[3])、B向上移动(@dx[1]) 40 | cnt += 1 if search([0] + maze + [0], a, 3, b, 1) 41 | } 42 | puts cnt 43 | -------------------------------------------------------------------------------- /zh_CN/q59_03.rb: -------------------------------------------------------------------------------- 1 | # 设置搜索的边界 2 | W, H = 4, 4 3 | # 从单元格顶点有没有往上下左右方向的线 4 | # U: 上, D: 下, L: 左, R: 右用比特列设置方向 5 | U, D, L, R = 0b1000, 0b0100, 0b0010, 0b0001 6 | 7 | # 单元格顶点只计算内侧,因此行列减1 8 | @width, @height = W - 1, H - 1 9 | # 设置单元格顶点的可能状态(按上述说明顺序) 10 | @dir = [U|D, L|R, U|D|L, U|D|R, U|L|R, D|L|R, U|D|L|R, 0b0] 11 | @cnt, @cnt1x1 = 0, 0 12 | @cross = [] 13 | 14 | def search(pos) 15 | if pos == @width * @height then # 搜索结束 16 | @cnt += 1 17 | # 求1x1的单元格 18 | cell = Array.new(W * H, true) 19 | @cross.each_with_index{|c, i| 20 | x, y = i % @width, i / @width 21 | cell[x + y * W] = false if (c & U == 0) || (c & L == 0) 22 | cell[(x+1) + y * W] = false if (c & U == 0) || (c & R == 0) 23 | cell[x + (y+1) * W] = false if (c & D == 0) || (c & L == 0) 24 | cell[(x+1) + (y+1) * W] = false if (c & D == 0) || (c & R == 0) 25 | } 26 | @cnt1x1 += 1 if cell.index(true) == nil 27 | return 28 | end 29 | @dir.each{|d| 30 | @cross[pos] = d 31 | # 最左侧或者左侧的线和右侧的线重合时 32 | # 最上面或者上面的线和下面的线重合时 33 | if ((pos % @width == 0) || 34 | ((@cross[pos] & L > 0) == (@cross[pos - 1] & R > 0))) && 35 | ((pos / @height == 0) || 36 | ((@cross[pos] & U > 0) == (@cross[pos - @height] & D > 0))) 37 | then 38 | search(pos + 1) 39 | end 40 | } 41 | end 42 | 43 | search(0) 44 | puts @cnt 45 | puts @cnt1x1 46 | -------------------------------------------------------------------------------- /ja_JP/q60_01.rb: -------------------------------------------------------------------------------- 1 | # 探索するサイズの設定 2 | W, H = 4, 4 3 | 4 | # 探索する関数 5 | # pos : 探索する位置 6 | # cells : セルが使用済みかどうかを全セルについてtrue/falseで保持 7 | # is1x1 : 1×1のセルがあるかどうか 8 | # 返り値 : 結合でできるパターン数と、1×1のセルが無いパターン数 9 | def search(pos, cells, is1x1) 10 | if pos == W * H then # 探索終了 11 | if is1x1 then 12 | return [1, 0] 13 | else 14 | return [1, 1] 15 | end 16 | end 17 | 18 | # 探索する位置が探索済みの場合、次の位置に移動 19 | return search(pos + 1, cells, is1x1) if cells[pos] 20 | 21 | # 長方形を順次探索 22 | x, y = pos % W, pos / W 23 | result = [0, 0] 24 | (1..(H - y)).each{|dy| # 垂直方向の大きさ 25 | (1..(W - x)).each{|dx| # 水平方向の大きさ 26 | next_cells = cells.clone 27 | settable = true # 長方形をセットできるか 28 | dy.times{|h| 29 | dx.times{|w| 30 | if next_cells[(x + w) + (y + h) * W] then 31 | # 既にセット済みの場合 32 | settable = false 33 | else 34 | next_cells[(x + w) + (y + h) * W] = true 35 | end 36 | } 37 | } 38 | if settable then 39 | # 長方形をセット可能な場合、セットして次を探索 40 | res = search(pos + 1, next_cells, 41 | is1x1 || (dx == 1 && dy == 1)) 42 | result[0] += res[0] 43 | result[1] += res[1] 44 | end 45 | } 46 | } 47 | return result 48 | end 49 | 50 | # セルの初期化 51 | cells = Array.new(W * H, false) 52 | puts search(0, cells, false) 53 | -------------------------------------------------------------------------------- /zh_CN/q26_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 10, 10 2 | # 设置停车场状态(用数字“9”作为边界) 3 | parking = Array.new(W + 2){Array.new(H + 2){1}} 4 | (W + 2).times{|w| 5 | parking[w][0] = parking[w][H + 1] = 9 6 | } 7 | (H + 2).times{|h| 8 | parking[0][h] = parking[W + 1][h] = 9 9 | } 10 | 11 | # 目标是左上角车的状态 12 | @goal = Marshal.load(Marshal.dump(parking)) 13 | @goal[1][1] = 2 14 | 15 | # 开始位置是右下角的状态 16 | start = Marshal.load(Marshal.dump(parking)) 17 | start[W][H] = 2 18 | 19 | def search(prev, depth) 20 | target = [] 21 | prev.each{|parking, w, h| 22 | # 上下左右移动 23 | [[-1, 0], [1, 0], [0, -1], [0, 1]].each{|dw, dh| 24 | nw, nh = w + dw, h + dh 25 | if (parking[nw][nh] != 9) then 26 | # 如果是边界以外的情况,则检查是否已经遍历 27 | temp = Marshal.load(Marshal.dump(parking)) 28 | temp[w][h], temp[nw][nh] = temp[nw][nh], temp[w][h] 29 | if !@log.has_key?([temp, nw, nh]) then 30 | # 把未遍历的位置作为遍历目标 31 | target.push([temp, nw, nh]) 32 | @log[[temp, nw, nh]] = depth + 1 33 | end 34 | end 35 | } 36 | } 37 | return if target.include?([@goal, W, H]) 38 | # 广度优先搜索 39 | search(target, depth + 1) if target.size > 0 40 | end 41 | 42 | # 记录已搜索部分 43 | @log = {} 44 | @log[[start, W, H - 1]] = 0 45 | @log[[start, W - 1, H]] = 0 46 | # 从开始位置开始搜索 47 | search([[start, W, H - 1], [start, W - 1, H]], 0) 48 | # 输出到达目标的搜索次数 49 | puts @log[[@goal, W, H]] 50 | -------------------------------------------------------------------------------- /ja_JP/q60_03.rb: -------------------------------------------------------------------------------- 1 | # サイズの設定 2 | W, H = 4, 4 3 | # 格子点から上下左右に線が出ているかどうか 4 | # U: 上, D: 下, L: 左, R: 右をビット列でセット 5 | U, D, L, R = 0b1000, 0b0100, 0b0010, 0b0001 6 | 7 | # 格子点の数は内側のため、行と列が1少ない 8 | @width, @height = W - 1, H - 1 9 | # 格子点として可能な形をセット(上記の説明の順番) 10 | @dir = [U|D, L|R, U|D|L, U|D|R, U|L|R, D|L|R, U|D|L|R, 0b0] 11 | @cnt, @cnt1x1 = 0, 0 12 | @cross = [] 13 | 14 | def search(pos) 15 | if pos == @width * @height then # 探索終了 16 | @cnt += 1 17 | # 1x1のセルを求める 18 | cell = Array.new(W * H, true) 19 | @cross.each_with_index{|c, i| 20 | x, y = i % @width, i / @width 21 | cell[x + y * W] = false if (c & U == 0) || (c & L == 0) 22 | cell[(x+1) + y * W] = false if (c & U == 0) || (c & R == 0) 23 | cell[x + (y+1) * W] = false if (c & D == 0) || (c & L == 0) 24 | cell[(x+1) + (y+1) * W] = false if (c & D == 0) || (c & R == 0) 25 | } 26 | @cnt1x1 += 1 if cell.index(true) == nil 27 | return 28 | end 29 | @dir.each{|d| 30 | @cross[pos] = d 31 | # 左端の場合、または左隣からの線が右からの線と一致する。 32 | # または上端の場合、または上隣からの線が下からの線と一致する。 33 | if ((pos % @width == 0) || 34 | ((@cross[pos] & L > 0) == (@cross[pos - 1] & R > 0))) && 35 | ((pos / @height == 0) || 36 | ((@cross[pos] & U > 0) == (@cross[pos - @height] & D > 0))) 37 | then 38 | search(pos + 1) 39 | end 40 | } 41 | end 42 | 43 | search(0) 44 | puts @cnt 45 | puts @cnt1x1 46 | -------------------------------------------------------------------------------- /ja_JP/q64_02.rb: -------------------------------------------------------------------------------- 1 | N = 5 2 | MASK = (1 << (N * N)) - 1 3 | # 移動した位置をビット演算で算出 4 | @move = [lambda{|m| (m >> 1) & 0b0111101111011110111101111}, 5 | lambda{|m| (m << N) & MASK}, 6 | lambda{|m| (m << 1) & 0b1111011110111101111011110}, 7 | lambda{|m| m >> N}] 8 | 9 | # 有効な迷路かを判定 10 | def enable(maze) 11 | man = (1 << (N * N - 1)) & (MASK - maze) # 左上からスタート 12 | while true do 13 | next_man = man 14 | @move.each{|m| next_man |= m.call(man)} # 上下左右に移動 15 | next_man &= (MASK - maze) # 壁以外の部分が移動可能 16 | return true if next_man & 1 == 1 # 右下にたどり着けば有効 17 | break if man == next_man 18 | man = next_man 19 | end 20 | false 21 | end 22 | 23 | # map:壁の配置 24 | # p1, d1: 1人目の位置、移動方向 25 | # p2, d2: 2人目の位置、移動方向 26 | def search(maze, p1, d1, p2, d2, turn) 27 | if turn then 28 | return true if p1 == p2 # 2人が出会った 29 | # どちらかのゴールに着いた 30 | return false if (p1 == 1) || (p2 == 1 << (N * N - 1)) 31 | end 32 | @move.size.times{|i| # 右手法で動ける方向を探索 33 | d = (d1 - 1 + i) % @move.size 34 | if @move[d].call(p1) & (MASK - maze) > 0 then 35 | return search(maze, p2, d2, @move[d].call(p1), d, !turn) 36 | end 37 | } 38 | false 39 | end 40 | 41 | cnt = 0 42 | (1 << N * N).times{|maze| 43 | if enable(maze) then 44 | man_a, man_b = 1 << (N * N - 1), 1 45 | cnt += 1 if search(maze, man_a, 3, man_b, 1, true) 46 | end 47 | } 48 | puts cnt 49 | -------------------------------------------------------------------------------- /ja_JP/q26_01.rb: -------------------------------------------------------------------------------- 1 | W, H = 10, 10 2 | # 駐車場の配置を設定(周囲に番兵として「9」をセット) 3 | parking = Array.new(W + 2){Array.new(H + 2){1}} 4 | (W + 2).times{|w| 5 | parking[w][0] = parking[w][H + 1] = 9 6 | } 7 | (H + 2).times{|h| 8 | parking[0][h] = parking[W + 1][h] = 9 9 | } 10 | 11 | # ゴールは左上に目的の車がある状態 12 | @goal = Marshal.load(Marshal.dump(parking)) 13 | @goal[1][1] = 2 14 | 15 | # 開始位置は右下に目的の車がある状態 16 | start = Marshal.load(Marshal.dump(parking)) 17 | start[W][H] = 2 18 | 19 | def search(prev, depth) 20 | target = [] 21 | prev.each{|parking, w, h| 22 | # 上下左右に移動 23 | [[-1, 0], [1, 0], [0, -1], [0, 1]].each{|dw, dh| 24 | nw, nh = w + dw, h + dh 25 | if (parking[nw][nh] != 9) then 26 | # 番兵以外の場合、過去に調べていないか調査 27 | temp = Marshal.load(Marshal.dump(parking)) 28 | temp[w][h], temp[nw][nh] = temp[nw][nh], temp[w][h] 29 | if !@log.has_key?([temp, nw, nh]) then 30 | # 過去に調べていないものを調査対象に追加 31 | target.push([temp, nw, nh]) 32 | @log[[temp, nw, nh]] = depth + 1 33 | end 34 | end 35 | } 36 | } 37 | return if target.include?([@goal, W, H]) 38 | # 幅優先探索で調査 39 | search(target, depth + 1) if target.size > 0 40 | end 41 | 42 | # 探索済みを記録 43 | @log = {} 44 | @log[[start, W, H - 1]] = 0 45 | @log[[start, W - 1, H]] = 0 46 | # 開始位置から探索開始 47 | search([[start, W, H - 1], [start, W - 1, H]], 0) 48 | # ゴールまでの探索数を出力 49 | puts @log[[@goal, W, H]] 50 | -------------------------------------------------------------------------------- /zh_CN/q62_01.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | WEEKS, DAYS = 6, 7 3 | 4 | # 读入假日数据文件 5 | @holiday = IO.readlines("q62-holiday.txt").map{|h| 6 | h.split('/').map(&:to_i) 7 | } 8 | # 读入调休工作日数据文件 9 | @extra_workday = IO.readlines("q62-extra-workday.txt").map{|h| 10 | h.split('/').map(&:to_i) 11 | } 12 | 13 | # 计算符合条件的最大长方形的面积 14 | def max_rectangle(cal) 15 | rect = 0 16 | WEEKS.times{|sr| # 起始行 17 | DAYS.times{|sc| # 起始列 18 | sr.upto(WEEKS){|er| # 终点行 19 | sc.upto(DAYS){|ec| # 终点列 20 | is_weekday = true # 起始点和终点之间有没有工作日以外的日子 21 | sr.upto(er){|r| 22 | sc.upto(ec){|c| 23 | is_weekday = false if cal[c + r * DAYS] == 0 24 | } 25 | } 26 | if is_weekday then 27 | rect = [rect, (er - sr + 1) * (ec - sc + 1)].max 28 | end 29 | } 30 | } 31 | } 32 | } 33 | rect 34 | end 35 | 36 | # 指定年份月份,获取最大长方形面积 37 | def calc(y, m) 38 | cal = Array.new(WEEKS * DAYS, 0) 39 | first = wday = Date.new(y, m, 1).wday # 获取该月1日的星期 40 | Date.new(y, m, -1).day.times{|d| # 循环处理直到该月结束 41 | if (1 <= wday && wday <= 5 && !@holiday.include?([y, m, d + 1])) || @extra_workday.include?([y, m, d + 1]) 42 | cal[first + d] = 1 43 | end 44 | wday = (wday + 1) % DAYS 45 | } 46 | max_rectangle(cal) 47 | end 48 | 49 | yyyymm = [*2006..2015].product([*1..12]) 50 | puts yyyymm.map{|y ,m| calc(y, m)}.inject(:+) 51 | -------------------------------------------------------------------------------- /zh_CN/q63_02.rb: -------------------------------------------------------------------------------- 1 | N = 5 2 | MASK = (1 << (N * N)) - 1 3 | # 利用位运算计算已经移动的位置 4 | @move = [lambda{|m| (m >> 1) & 0b0111101111011110111101111}, 5 | lambda{|m| (m << N) & MASK}, 6 | lambda{|m| (m << 1) & 0b1111011110111101111011110}, 7 | lambda{|m| m >> N}] 8 | 9 | # 判断有效路径 10 | def enable(maze) 11 | man = (1 << (N * N - 1)) & (MASK - maze) # 从左上角出发 12 | while true do 13 | next_man = man 14 | @move.each{|m| next_man |= m.call(man)} # 上下左右移动 15 | next_man &= (MASK - maze) # 可以移动到墙壁以外的方格 16 | return true if next_man & 1 == 1 # 到达右下角有效 17 | break if man == next_man 18 | man = next_man 19 | end 20 | false 21 | end 22 | 23 | # maze: 墙壁设置 24 | # p1, d1: 第1个人走过的路径和移动方向 25 | # p2, d2: 第2个人走过的路径和移动方向 26 | def search(maze, p1, d1, p2, d2, turn) 27 | if true then 28 | return true if p1 == p2 # 两人相遇 29 | # 其中一人到达目标 30 | return false if (p1 == 1) || (p2 == 1 << (N * N - 1)) 31 | end 32 | @move.size.times{|i| # 搜索右手法则指定的方向 33 | d = (d1 - 1 + i) % @move.size 34 | if @move[d].call(p1) & (MASK - maze) > 0 then 35 | return search(maze, p2, d2, @move[d].call(p1), d, !turn) 36 | end 37 | } 38 | false 39 | end 40 | 41 | cnt = 0 42 | (1 << N * N).times{|maze| 43 | if enable(maze) then 44 | man_a, man_b = 1 << (N * N - 1), 1 45 | cnt += 1 if search(maze, man_a, 3, man_b, 1, true) 46 | end 47 | } 48 | puts cnt 49 | -------------------------------------------------------------------------------- /zh_CN/q60_02.rb: -------------------------------------------------------------------------------- 1 | # 长方形大小 2 | W, H = 5, 4 3 | @width, @height = W + 2, H + 2 4 | 5 | NONE, BLUE, WHITE, WALL = 0, 1, 2, 9 6 | 7 | map = Array.new(@width * @height, 0) 8 | # 设置外边界 9 | @width.times{|i| 10 | map[i] = WALL 11 | map[i + @width * (@height - 1)] = WALL 12 | } 13 | @height.times{|i| 14 | map[i * @width] = WALL 15 | map[(i + 1) * @width - 1] = WALL 16 | } 17 | 18 | # 从(1,1)开始 19 | map[@width + 1] = BLUE 20 | @maps = {map => false} 21 | 22 | # 采用广度优先递归地对格子涂色 23 | def fill(depth, color) 24 | return if depth == 0 25 | new_maps = {} 26 | W.times{|w| 27 | H.times{|h| 28 | pos = w + 1 + (h + 1) * @width 29 | @maps.each{|k, v| 30 | check = false 31 | if k[pos] == 0 then 32 | [1, -1, @width, -@width].each{|d| 33 | check = true if k[pos + d] == color 34 | } 35 | end 36 | if check then 37 | m = k.clone 38 | m[pos] = color 39 | new_maps[m] = false 40 | end 41 | } 42 | } 43 | } 44 | @maps = new_maps 45 | fill(depth - 1, color) 46 | end 47 | 48 | # 把一半方格涂成蓝色 49 | fill(W * H / 2 - 1, BLUE) 50 | 51 | # 把白色涂进空着的方格上 52 | new_maps = {} 53 | @maps.each{|k, v| 54 | pos = k.index(NONE) 55 | m = k.clone 56 | m[pos] = WHITE 57 | new_maps[m] = false 58 | } 59 | @maps = new_maps 60 | 61 | # 涂上白色 62 | fill(W * H / 2 - 1, WHITE) 63 | 64 | # 统计所有方格全部上色完毕的组合 65 | count = 0 66 | @maps.each{|m| 67 | count += 1 if !(m.include?(NONE)) 68 | } 69 | puts count 70 | -------------------------------------------------------------------------------- /zh_CN/q58_02.rb: -------------------------------------------------------------------------------- 1 | @n = 8 2 | # 包含丢手绢的人 3 | @all = (0..@n).to_a 4 | 5 | # 初始状态 6 | start = {} 7 | start[(1..@n).to_a] = [] 8 | 9 | # 终止状态 10 | goal = {} 11 | @n.times{|i| 12 | goal[(1..@n).to_a.reverse.rotate(i)] = [] 13 | } 14 | 15 | # 求移动距离 16 | def dist(log) 17 | return 0 if log.size == 0 18 | check = log.clone 19 | pre = check.shift 20 | sum = @n + pre 21 | check.each{|c| 22 | sum += @n + (c + @n - pre) % @n 23 | pre = c 24 | } 25 | sum 26 | end 27 | 28 | # 搜索(direction为true时是顺序方向,false时为逆序方向) 29 | def search(child, direction) 30 | child.clone.each{|key, value| 31 | oni = (@all - key)[0] # 没有被使用的就是丢手绢的人 32 | @n.times{|i| 33 | k = key.clone 34 | k[i] = oni 35 | v = value + [i] 36 | if child.has_key?(k) then 37 | if direction then # 顺序方向 38 | child[k] = v if dist(v) < dist(child[k]) 39 | else # 逆序方向 40 | child[k] = v if dist(v.reverse) < dist(child[k].reverse) 41 | end 42 | else 43 | child[k] = v 44 | end 45 | } 46 | } 47 | end 48 | 49 | cnt = 0 50 | while (start.keys & goal.keys).size == 0 do 51 | if cnt % 2 == 0 then # 偶数时顺序方向搜索 52 | search(start, cnt % 2 == 0) 53 | else # 奇数时逆序方向搜索 54 | search(goal, cnt % 2 == 0) 55 | end 56 | cnt += 1 57 | end 58 | 59 | # 双向搜索结果合流时,计算最短移动距离 60 | min = 98 61 | (start.keys & goal.keys).each{|c| 62 | d = dist(start[c] + goal[c].reverse) 63 | min = [min, d].min 64 | } 65 | 66 | puts min 67 | -------------------------------------------------------------------------------- /ja_JP/q59_02.rb: -------------------------------------------------------------------------------- 1 | @n = 8 2 | # 鬼を含んだ 3 | @all = (0..@n).to_a 4 | 5 | # 開始時の配置 6 | start = {} 7 | start[(1..@n).to_a] = [] 8 | 9 | # 終了時の配置 10 | goal = {} 11 | @n.times{|i| 12 | goal[(1..@n).to_a.reverse.rotate(i)] = [] 13 | } 14 | 15 | # 移動距離を求める 16 | def dist(log) 17 | return 0 if log.size == 0 18 | check = log.clone 19 | pre = check.shift 20 | sum = @n + pre 21 | check.each{|c| 22 | sum += @n + (c + @n - pre) % @n 23 | pre = c 24 | } 25 | sum 26 | end 27 | 28 | # 探索(directionがtrueのとき順方向、falseのとき逆方向) 29 | def search(child, direction) 30 | child.clone.each{|key, value| 31 | oni = (@all - key)[0] # 使われていないのが鬼 32 | @n.times{|i| 33 | k = key.clone 34 | k[i] = oni 35 | v = value + [i] 36 | if child.has_key?(k) then 37 | if direction then # 順方向 38 | child[k] = v if dist(v) < dist(child[k]) 39 | else # 逆方向 40 | child[k] = v if dist(v.reverse) < dist(child[k].reverse) 41 | end 42 | else 43 | child[k] = v 44 | end 45 | } 46 | } 47 | end 48 | 49 | cnt = 0 50 | while (start.keys & goal.keys).size == 0 do 51 | if cnt % 2 == 0 then # 偶数のときは順方向に探索 52 | search(start, cnt % 2 == 0) 53 | else # 奇数のときは逆方向に探索 54 | search(goal, cnt % 2 == 0) 55 | end 56 | cnt += 1 57 | end 58 | 59 | # 両方向からの探索結果が合流した場合、最短の移動距離を算出 60 | min = 98 61 | (start.keys & goal.keys).each{|c| 62 | d = dist(start[c] + goal[c].reverse) 63 | min = [min, d].min 64 | } 65 | 66 | puts min 67 | -------------------------------------------------------------------------------- /ja_JP/q61_02.rb: -------------------------------------------------------------------------------- 1 | # 盤面のサイズ 2 | W, H = 5, 4 3 | @width, @height = W + 2, H + 2 4 | 5 | NONE, BLUE, WHITE, WALL = 0, 1, 2, 9 6 | 7 | map = Array.new(@width * @height, 0) 8 | # 外枠を作成 9 | @width.times{|i| 10 | map[i] = WALL 11 | map[i + @width * (@height - 1)] = WALL 12 | } 13 | @height.times{|i| 14 | map[i * @width] = WALL 15 | map[(i + 1) * @width - 1] = WALL 16 | } 17 | 18 | # 最初は(1, 1)からスタート 19 | map[@width + 1] = BLUE 20 | @maps = {map => false} 21 | 22 | # 選択した色で埋めることを幅優先探索で再帰的に行う 23 | def fill(depth, color) 24 | return if depth == 0 25 | new_maps = {} 26 | W.times{|w| 27 | H.times{|h| 28 | pos = w + 1 + (h + 1) * @width 29 | @maps.each{|k, v| 30 | check = false 31 | if k[pos] == 0 then 32 | [1, -1, @width, -@width].each{|d| 33 | check = true if k[pos + d] == color 34 | } 35 | end 36 | if check then 37 | m = k.clone 38 | m[pos] = color 39 | new_maps[m] = false 40 | end 41 | } 42 | } 43 | } 44 | @maps = new_maps 45 | fill(depth - 1, color) 46 | end 47 | 48 | # 青色を半分まで埋める 49 | fill(W * H / 2 - 1, BLUE) 50 | 51 | # 白色を空いている最初の位置に入れる 52 | new_maps = {} 53 | @maps.each{|k, v| 54 | pos = k.index(NONE) 55 | m = k.clone 56 | m[pos] = WHITE 57 | new_maps[m] = false 58 | } 59 | @maps = new_maps 60 | 61 | # 白色を埋める 62 | fill(W * H / 2 - 1, WHITE) 63 | 64 | # すべて埋まっているものをカウント 65 | count = 0 66 | @maps.each{|m| 67 | count += 1 if !(m.include?(NONE)) 68 | } 69 | puts count 70 | --------------------------------------------------------------------------------