これをツリーの問題として考えると、それは赤いニシンであり、実際には有向グラフです。しかし、それについてはすべて忘れてください。
一番上のガラスの下にあるガラスを考えてください。その上に1つまたは2つのグラスがあり、そこにあふれることがあります。座標系を適切に選択すれば(心配する必要はありません。最後を参照)、任意のグラスの「親」グラスを取得する関数を作成できます。
これで、ガラスからのオーバーフローに関係なく、ガラスに注がれた液体の量を取得するアルゴリズムを考えることができます。しかし、答えは、多くの液体が各親に注がれ、各親グラスに保存されている量を2で割ったものです。amount_poured_into()関数の本体のpythonフラグメントとしてこれを書く:
# p is coords of the current glass
amount_in = 0
for pp in parents(p):
amount_in += max((amount_poured_into(total, pp) - 1.0)/2, 0)
max()は、負のオーバーフローが発生しないようにするためのものです。
ほぼ完成です!ページの下に「y」、1行目が0、2行目が1などの座標系を選択します。「x」座標は最上行のガラスの下にゼロを持ち、2行目は-1のx座標を持ち、 +1、3番目の行-2、0、+ 2など。重要な点は、レベルyの左または右端のガラスがabs(x)= yになることです。
これらすべてをpython(2.x)にまとめると、次のようになります。
def parents(p):
"""Get parents of glass at p"""
(x, y) = p
py = y - 1 # parent y
ppx = x + 1 # right parent x
pmx = x - 1 # left parent x
if abs(ppx) > py:
return ((pmx,py),)
if abs(pmx) > py:
return ((ppx,py),)
return ((pmx,py), (ppx,py))
def amount_poured_into(total, p):
"""Amount of fluid poured into glass 'p'"""
(x, y) = p
if y == 0: # ie, is this the top glass?
return total
amount_in = 0
for pp in parents(p):
amount_in += max((amount_poured_into(total, pp) - 1.0)/2, 0)
return amount_in
def amount_in(total, p):
"""Amount of fluid left in glass p"""
return min(amount_poured_into(total, p), 1)
そのため、実際にガラスの量をpで取得するには、amount_in(total、p)を使用します。
OPからは明らかではありませんが、「パラメーターを追加できない」ということは、表示されているガラスの数に関して元の質問に答えなければならないことを意味する場合があります。これは、ショーガラス番号から上記で使用した内部座標系へのマッピング関数を記述することで解決されます。面倒ですが、反復解法または数学解法のいずれかを使用できます。わかりやすい反復関数:
def p_from_n(n):
"""Get internal coords from glass 'number'"""
for (y, width) in enumerate(xrange(1, n+1)):
if n > width:
n -= width
else:
x = -y + 2*(n-1)
return (x, y)
ここで、ガラスの数を受け入れるように上記のamount_in()関数を書き換えます。
def amount_in(total, n):
"""Amount of fluid left in glass number n"""
p = p_from_n(n)
return min(amount_poured_into(total, p), 1)