Found this problem in hackerrank.
One day Bob drew a tree, with \$n\$ nodes and \$n-1\$ edges on a piece of paper. He soon discovered that parent of a node depends on the root of the tree. The following images shows an example of that:
Learning the fact, Bob invented an exciting new game and decided to play it with Alice. The rules of the game is described below:
Bob picks a random node to be the tree's root and keeps the identity of the chosen node a secret from Alice. Each node has an equal probability of being picked as the root.
Alice then makes a list of \$g\$ guesses, where each guess is in the form \$u, v\$ and means Alice guesses that \${\rm parent}(v) = u\$ is true. It's guaranteed that an undirected edge connecting \$u\$ and \$v\$ exists in the tree.
For each correct guess, Alice earns one point. Alice wins the game if she earns at least \$k\$ points (i.e., at least \$k\$ of her guesses were true).
Alice and Bob play \$q\$ games. Given the tree, Alice's guesses, and the value of \$k\$ for each game, find the probability that Alice will win the game and print it on a new line as a reduced fraction in the format
p/q
.
Solution: There is a tree with some edges marked with arrows. For every vertex in a tree you have to count how many arrows point towards it. For one fixed vertex this may be done via one depth-first search (DFS). Every arrow that was traversed during DFS in direction opposite to its own adds 1. If you know the answer for vertex \$v\$, you can compute the answer for vertex \$u\$ adjacent to \$v\$ in \$O(1)\$.
It's almost the same as for \$v\$, but if there are arrows \$u→v\$ or \$v→u\$, their contributions are reversed. Now you can make the vertex \$u\$ crawl over the whole graph by moving to adjacent vertices in the second DFS.
def gcd(a, b):
if not b:
return a
return gcd(b, a%b)
def dfs1(m, guess, root, seen):
'''keep 1 node as root and calculate how many arrows are pointing towards it'''
count = 0
stack = []
stack.append(root)
seen.add(root)
while len(stack):
root = stack.pop(len(stack)-1)
for i in m[root]:
if i not in seen:
seen.add(i)
count += (1 if root in guess and i in guess[root] else 0)
stack.append(i)
return count
def dfs2(m, guess, root, seen, cost, k):
'''now make every node as root and calculate how many nodes
are pointed towards it; If u is the root node for which
dfs1 calculated n (number of arrows pointed towards the root)
then for v (adjacent node of u), it would be n-1 as v is the
made the parent now in this step (only if there is a guess, if
there is no guess then it would be not changed)'''
stack = []
stack.append((root, cost))
seen.add(root)
t_win = 0
while len(stack):
(root, cost) = stack.pop(len(stack)-1)
t_win += cost >= k
for i in m[root]:
if i not in seen:
seen.add(i)
stack.append((i, cost - (1 if root in guess and i in guess[root] else 0) + (1 if i in guess and root in guess[i] else 0)))
return t_win
q = int(raw_input().strip())
for a0 in xrange(q):
n = int(raw_input().strip())
m = {}
guess = {}
seen = set()
for a1 in xrange(n-1):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
if u not in m:
m[u] = []
m[u].append(v)
if v not in m:
m[v] = []
m[v].append(u)
g,k = raw_input().strip().split(' ')
g,k = [int(g),int(k)]
for a1 in xrange(g):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
if u not in guess:
guess[u] = []
guess[u].append(v)
cost = dfs1(m, guess, 1, seen)
seen = set()
win = dfs2(m, guess, 1, seen, cost, k)
g = gcd(win, n)
print("{0}/{1}".format(win/g, n/g))