技術メモ

役に立てる技術的な何か、時々自分用の覚書。幅広く色々なことに興味があります。

カウントダウン数列を考える

カウントダウン数列を考える

京都大学の学園祭の看板で四則演算の組み合わせだけでカウントダウンを表現するというのが話題になっているようだ。 そこで、同じ仕組みで色々な数列に対してどれだけのカウントダウンができるのかを考えてみた。

京都大学の学祭カウントダウンが頭良すぎて感心してしまう→実際できるのか検証してみた

補足として365日前からカウントダウンするにはどうすればいいかを考えてみる。

要件

  1. 与えられた数列に対し順序を固定しその間の四則演算の演算記号を組み替えることで出力を得る
  2. 1から順にどれだけカウントアップできるかを出力する
  3. できれば出力に使われた四則演算の組み合わせを見れるようにしたい

実装

動作環境 python3.10.6

from typing import List
import itertools

class Outputs:
    def __init__(self):
        self.equations: List[str] = []
        self.outputs: List[float] = []

    def add(self, equation, output):
        self.equations.append(equation)
        self.outputs.append(output)
        
    def find(self, num) -> str:
        try:
            index = self.outputs.index(num)
            return self.equations[index]
        except:
            raise Exception()
        
def count_down_nums(nums: List[int], dry_run: bool = True) -> int:
    check_outputs: List[int] = list(range(1,9999))
    operators: List[str] = ['+','-','*','/']
    outputs: Outputs = Outputs()
    operator_combinations = list(itertools.product(operators, repeat=len(nums)-1))
    for operator_combination in operator_combinations:
        equation: str = ''
        for i,num in enumerate(nums):
            if i==0:
                equation += str(num)
            else:
                equation += operator_combination[i-1]
                equation += str(num)
        outputs.add(equation, eval(equation))
    for i,check_output in enumerate(check_outputs):
        try:
            equation = outputs.find(check_output)
            if dry_run == False:
                print(equation +  '=' + str(check_output))
            continue
        except:
            if i==0:
                return 0
            return check_outputs[i-1]
    return -1 # means "more than 9999"

ケース1

まずは元ネタと同じ数列 [6,4,5,2,1] でやってみる

count_down_nums([6,4,5,2,1], dry_run=False)
6+4-5*2+1=1
6+4-5-2-1=2
6+4-5-2*1=3
6+4-5-2+1=4
6-4+5-2*1=5
6+4-5+2-1=6
6+4-5+2*1=7
6+4-5+2+1=8
6-4+5+2*1=9
6-4+5+2+1=10
6-4+5*2-1=11
6+4+5-2-1=12
6+4+5-2*1=13
6+4+5-2+1=14
6+4*5/2-1=15
6+4+5+2-1=16
6+4+5+2*1=17
6+4+5+2+1=18
6+4+5*2-1=19
6+4+5*2*1=20
6+4+5*2+1=21
6*4-5+2+1=22
6+4*5-2-1=23
6+4*5-2*1=24
6+4*5-2+1=25
6*4+5-2-1=26
6+4*5+2-1=27
6+4*5+2*1=28
6+4*5+2+1=29
6*4+5+2-1=30
6*4+5+2*1=31
6*4+5+2+1=32
6*4+5*2-1=33
6*4+5*2*1=34
6*4+5*2+1=35





35

この仕組だと35日前からカウントダウンできるらしい

ケース2

京都大学の学祭カウントダウンが頭良すぎて感心してしまう→実際できるのか検証してみた

要らないと言われた「3」の立場、気持ちを考えると胸が潰れそう…

2022/10/24 09:24

どうして3がないのだと言われていたので、順当に6からの降順 [6,5,4,3,2,1] でやってみる

count_down_nums([6,5,4,3,2,1], dry_run=False)
6+5-4-3-2-1=1
6+5-4-3-2*1=2
6+5-4-3-2+1=3
6+5-4*3/2-1=4
6+5-4-3+2-1=5
6+5-4-3+2*1=6
6+5-4+3-2-1=7
6+5+4-3*2-1=8
6+5+4-3-2-1=9
6+5+4-3-2*1=10
6+5+4-3-2+1=11
6+5-4+3+2*1=12
6+5+4-3+2-1=13
6+5+4-3+2*1=14
6+5+4+3-2-1=15
6+5+4+3-2*1=16
6+5+4+3-2+1=17
6+5+4*3/2+1=18
6+5+4+3+2-1=19
6+5+4+3+2*1=20
6+5+4+3+2+1=21
6+5+4+3*2+1=22
6*5-4*3/2-1=23
6+5+4*3+2-1=24
6+5+4*3+2*1=25
6+5+4*3+2+1=26
6+5*4+3-2*1=27
6+5*4+3-2+1=28
6*5+4-3-2*1=29
6+5*4+3+2-1=30
6+5*4+3+2*1=31
6+5*4+3+2+1=32
6+5*4+3*2+1=33
6+5+4*3*2-1=34
6+5+4*3*2*1=35
6+5+4*3*2+1=36
6+5*4*3/2+1=37
6*5+4+3+2-1=38
6*5+4+3+2*1=39
6*5+4+3+2+1=40
6*5+4+3*2+1=41
6*5*4/3+2*1=42
6*5+4*3+2-1=43
6*5+4*3+2*1=44
6*5+4*3+2+1=45
6*5/4*3*2+1=46





46

こっちのほうが表現力豊かじゃないか。 どうして京都大学の学祭委員の人たちは[6,5,4,3,2,1]にせずにあえて[6,4,5,2,1]なんて不規則な数列にしたのか気になる。(第64回だからか…)

ケース3

次は [7,6,5,4,3,2,1] でやってみる

count_down_nums([7,6,5,4,3,2,1])
64

ケース4

このまま増えていくとどこまでカウントダウンできるのか気になったので

  • [6,5,4,3,2,1]
  • [7,6,5,4,3,2,1]

...

とやってみる

print("6~1" ,count_down_nums(range(1,7)[::-1]))
print("7~1" ,count_down_nums(range(1,8)[::-1]))
print("8~1" ,count_down_nums(range(1,9)[::-1]))
print("9~1" ,count_down_nums(range(1,10)[::-1]))
print("10~1" ,count_down_nums(range(1,11)[::-1]))
print("11~1" ,count_down_nums(range(1,12)[::-1])) 
6~1 46
7~1 64
8~1 102
9~1 152
10~1 248
11~1 1133

ケース4

等比数列ならもっと表現力あるんじゃないか?

print("2^5~1" ,count_down_nums([32,16,8,4,2,1]))
print("2^6~1" ,count_down_nums([64,32,16,8,4,2,1]))
print("2^7~1" ,count_down_nums([128,64,32,16,8,4,2,1]))
print("2^8~1" ,count_down_nums([256,128,64,32,16,8,4,2,1]))
print("2^9~1" ,count_down_nums([512,256,128,64,32,16,8,4,2,1]))
2^5~1 59
2^6~1 139
2^7~1 283
2^8~1 595
2^9~1 1163

結論

365日をカウントダウンするなら

  • [11,10,9,9,7,6,5,4,3,2,1]
  • [256,128,64,32,16,8,4,2,1]

でできる