結果
| 問題 |
No.708 (+ー)の式
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2018-10-24 23:02:27 |
| 言語 | Python3 (3.13.1 + numpy 2.2.1 + scipy 1.14.1) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 5,701 bytes |
| コンパイル時間 | 384 ms |
| コンパイル使用メモリ | 12,800 KB |
| 実行使用メモリ | 11,136 KB |
| 最終ジャッジ日時 | 2024-11-19 05:38:08 |
| 合計ジャッジ時間 | 1,340 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 11 WA * 1 |
ソースコード
import sys
# 演算子(ホントは二項演算子もクラス化したい)
class Operator:
def __init__(self):
self.name = ''
def calc(self):
pass
def __str__(self):
return self.name
# +演算子(二項演算子)
class PlusOperator(Operator):
def __init__(self):
self.name = '+'
# 項を与えて演算を行う
def calc(self, val1, val2):
return val1.calc_value() + val2.calc_value()
# -演算子(二項演算子)
class MinusOperator(Operator):
def __init__(self):
self.name = '-'
# 項を与えて演算を行う
def calc(self, val1, val2):
return val1.calc_value() - val2.calc_value()
# 値
# 値を最後まで評価するには calc_value() を使う
class Value:
def __init__(self, v):
self.__val = v
def add_char(self, c):
self.__val = self.value() * 10 + int(c)
def value(self):
return self.__val
def calc_value(self):
v = self.value()
#sys.stderr.write("v={}\n".format(v))
while isinstance(v, Value):
if v is Value:
return v.__val
v = v.value()
return v
def make_exp(self, ope, v2):
return BinominalExpression(ope, self, v2)
def __str__(self):
return "{0}".format(self.__val)
# 式(値のサブクラス)
class Expression(Value):
def __init__(self, ope):
self.operator = ope
# 式を評価(1段階だけ)
def value(self):
raise 'Not implemented!'
# 二項式(式のサブクラス)
# 演算子と右辺値と左辺値を持つ
class BinominalExpression(Expression):
def __init__(self, ope, v1, v2):
super().__init__(ope)
self.val1 = v1
self.val2 = v2
# 式を評価(1段階だけ)
def value(self):
return self.operator.calc(self.val1, self.val2)
def __str__(self):
return "{0} {1} {2}".format(self.val1, self.operator, self.val2)
# カッコ(値のサブクラス)
# 値をカッコで囲んだ状態を表現する
class Brackets(Value):
def __init__(self, v):
super().__init__(v)
def __str__(self):
return "({0})".format(super().__str__())
# 式文字列のパーサー
class Parser:
def __init__(self):
self.__v1 = Value(0) # パース中の左辺値
self.__v2 = Value(0) # パース中の右辺値
self.__operator = None # パース中の演算子
# 式が生成可能であれば生成する
def try_make_exp(self):
if self.__operator != None:
self.__v1 = self.__v1.make_exp(self.__operator, self.__v2)
self.__operator = None
self.__v2 = Value(0)
# パーサー本体の処理
def parse(self, chars):
while len(chars) > 0:
c = chars.pop(0)
sys.stderr.write("c={0} # {1}\n".format(c, self))
if c == '(':
p = Parser()
sys.stderr.write("new parser = {0}\n".format(p))
b = Brackets(p.parse(chars)) # カッコの中を別のパーサーで処理してカッコで囲う
if self.__operator == None:
self.__v1 = b
else:
self.__v2 = b
elif c == ')':
self.try_make_exp()
break # カッコが終われば処理終了
elif c == '+':
self.try_make_exp()
self.__operator = PlusOperator()
elif c == '-':
self.try_make_exp()
self.__operator = MinusOperator()
else:
if self.__operator == None:
self.__v1.add_char(c)
else:
self.__v2.add_char(c)
self.try_make_exp()
return self.__v1
def __str__(self):
return "{3}: v1={0}, operator={1}, v2={2}".format(self.__v1, self.__operator, self.__v2, super().__str__())
chars = list(input())
p = Parser()
val = p.parse(chars)
print(val.value())
# 【感想】
# パーサーでは1文字ずつ線形に解析できるようにし、カッコは再帰処理で対応した。
# 式の構造を完全にオブジェクトで保持できるようにし、最後に評価を行うことで木構造を評価していくようにした。
# C# の Expression 関連のクラス構造を思い浮かべながら、近いものを構築していった。
# こうすることで動的に式構造を変更できるようなライブラリに発展させていける可能性が広がる
#
# クラス構成について
# 値 > 式 > 二項式 というクラスの継承関係にし、
# カッコも 値 のサブクラスとすることでネストに対応できるようにした。
# 二項式には2つの値と1つの演算子を所有させ、値を評価させると演算子のcalc()を呼んでくれる仕掛けにした。
# 値を評価することで、そのサブクラスが実際の評価処理を行っていく構造であり、、木構造のどのポイントからでも
# 評価が可能となっている。
#
# Python について
# 初挑戦の Python だったが、ググる際に Python と Python3 の区別ししないといけないことに気づいた。
# クラスのインスタンスメソッドの第1引数に self を書かないといけない点、また、インスタンスメンバに
# アクセスする際に self. を付けないといけない点など、JavaScriptのような感じでとても冗長な記述と感じた。
# この辺は Ruby とは違い、明示的に書く文化が良しとされているようだ。