将其视为树问题是一条红鲱鱼,实际上是有向图。但是,请忘记所有这些。
想想顶杯下方任何地方的玻璃杯。它上面会有一两个玻璃杯,可能会溢出。通过适当选择坐标系(不用担心,请参阅结尾),我们可以编写一个函数来获取任何给定玻璃的“父”玻璃。
现在,我们可以考虑一种算法,该算法可以使倒入玻璃杯的液体量与玻璃杯的溢出无关。答案是,将大量液体倒入每个父母玻璃杯中,然后减去储存在每个父母玻璃杯中的储水量除以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”的坐标系,第一行玻璃为0,第二行为1,依此类推。“ x”坐标在第一行玻璃下面为零,第二行的x坐标为-1和+1,第三行-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)