├── 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 |
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 |
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 |
--------------------------------------------------------------------------------