Pensar nisso como um problema de árvore é um problema, é realmente um gráfico direcionado. Mas esqueça tudo isso.
Pense em um copo em qualquer lugar abaixo do topo. Terá um ou dois copos acima dele que podem transbordar para ele. Com a escolha apropriada do sistema de coordenadas (não se preocupe, veja o final), podemos escrever uma função para obter os óculos "originais" de qualquer vidro.
Agora podemos pensar em um algoritmo para obter a quantidade de líquido derramado em um copo, independentemente do transbordamento desse copo. A resposta é, no entanto, muito líquido é derramado em cada progenitor menos a quantidade armazenada em cada copo progenitor, dividido por 2. Basta somar isso para todos os progenitores. Escrevendo isso como um fragmento python do corpo de uma função amount_poured_into ():
# 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)
O máximo () é para garantir que não recebamos uma quantidade negativa de excesso.
Estamos quase terminando! Escolhemos um sistema de coordenadas com 'y' na página, os óculos da primeira linha são 0, a segunda linha é 1 etc. As coordenadas 'x' têm um zero sob o vidro da linha superior e a segunda linha tem as coordenadas x de -1 e +1, terceira linha -2, 0, +2 e assim por diante. O ponto importante é que o copo mais à esquerda ou à direita no nível y terá abs (x) = y.
Embrulhando tudo isso em python (2.x), temos:
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)
Portanto, para obter a quantidade realmente em um copo em p, use amount_in (total, p).
Não está claro no OP, mas o pouco sobre "você não pode adicionar parâmetros" pode significar que a pergunta original deve ser respondida em termos dos números de vidro mostrados. Isso é resolvido escrevendo uma função de mapeamento dos números do vidro de exibição para o sistema de coordenadas interno usado acima. É complicado, mas pode ser usada uma solução iterativa ou matemática. Uma função iterativa fácil de entender:
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)
Agora basta reescrever a função amount_in () acima para aceitar um número de copo:
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)