* 逆ポーランド記法の問題を大量生産する
May 19 2014
とある友人に頼まれたのでやっつけで作った。
逆ポーランド記法に関してはこちらを参照。
スタックの概念を理解するために逆ポーランド記法の問題を処理するプログラムを書いたりする(らしい)。
こいつの問題を大量生産したいってなったとき、考えなきゃいけないことは思いついたやつでこんな感じ。
- 問題の先頭2つは必ず数字でなければならない
- 記号、数字の数を
x, y
とすると、先頭からそれぞれ数えた時に常にx <= y - 1
でなければいけない
… アキュムレータに2つ以上数字が無いと記号が積まれた時に処理が行えないため - 無理数などが生まれてはいけない
… 今回はランダム生成する数に0を入れないことで対処 - いい感じにランダムにできたらオサレ
こんな感じでしょうか。
これに加えて負の数、浮動小数点を加えるかどうかを選択するようにしました。
コードが以下の感じ。
#!/usr/bin/python # -*- coding: utf-8 -*- import random DECIMEL, MINUS = 10, 4 # 小数点/負の数の出現頻度 1/variable name def randnum(d, m): num = random.randint(1, 9) if d: num = randdecimel(num) if m: num = randminus(num) return num def randdecimel(num): return num if random.randint(0, DECIMEL) != 0 else float(format(random.random(), '.1f')) + float(num) def randminus(num): return num if random.randint(0, MINUS) != 0 else num * -1 ans = [] m = eval(input('生成する問題数を入力してください (1 <= M <= 10000)')) n = eval(input('問題の最大桁数を入力してください (3 <= N <= 100)')) decimel = True if input("小数点は入れます? Y/n") == "Y" else False minus = True if input("負の数は入れます? Y/n") == "Y" else False for i in range(m): f = random.randint(3, n) # 問題桁数の決定 while f % 2 == 0: f = random.randint(3, n) q = [] # 問題 num = [randnum(decimel, minus) for j in range(int(f / 2 + 1))] obj = [['+', '-', '*', '/'][random.randint(0,3)] for j in range(int(f / 2))] n1, n2 = 0, 0 # 数字/符号の数 while len(q) < f: if len(num) == 0: q += obj # 数字が尽きた場合 break if n1 - n2 < 2: q.append(num.pop()) n1 += 1 else: tmp = random.randint(0, 1) if tmp == 0: q.append(num.pop()) n1 += 1 else: q.append(obj.pop()) n2 += 1 print(" ".join(map(str, q)))
ついでにソルバーも載せておく。
#!/usr/bin/python def rpn(stack, obj): if type(obj) == int: stack.append(obj) else: p = stack.pop() if obj == '+': stack.append(stack.pop() + p) elif obj == '-': stack.append(stack.pop() - p) elif obj == '*': stack.append(stack.pop() * p) elif obj == '/': stack.append(stack.pop() / p) return stack while True: stack = [] print("半角スペース区切りで問題を入力してください") formula = input("-> ").split() try: for f in formula: stack = rpn(stack, int(f) if f.isdigit() else f) print(stack[0]) except: print('Error: invalid input') break
実行すると以下のようにやりとりできる
% python3 rpn_gene.py 生成する問題数を入力してください (1 <= N <= 10000) 10000 問題の最大桁数を入力してください (3 <= N <= 100) 100 小数点は入れます? Y/n Y 負の数は入れます? Y/n Y ~ ここ以下で問題生成 ~
以上!
【追記】
関数化して少しだけ改良した。
https://gist.github.com/sota1235/906d56098b9da9815913
※この記事は WordPress に投稿した記事を変換したものです。一部不自然な表示があるかも知れません。ご了承ください。また、記事タイトル先頭の * は WordPress から移行した記事である印です。