Problem:


	MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

夏合宿の朝は早い

JAG夏合宿の朝は早い．
正確にはそこまで早くないが，早いと感じる参加者が多いという．

例年合宿の会場となる施設では，退去時に参加者がシーツの回収や掃除をしなければならない．
1 つの部屋でも退去が遅れると，来年以降の施設の利用に関わるため，参加者は一人たりとも寝坊してはならない．

そうは言っても皆人間，寝坊することもある．
しかし，起きた人が連絡先を知っている人にモーニングコールをすることで，一人も寝坊しないよう努めることができるはずだ．

JAG夏合宿の運営を任されたあなたは，寝坊を絶対に防ぐ手を打つための前準備として，どのくらいの確率で全員がきちんと起きられるのかを調べることにした．
準備としてまず，各参加者の寝坊する確率と，各々が連絡先を知っている人のリストを入手した．
ここで，部屋は個室であるため，各々が寝坊するか否かは，他の参加者が寝坊するか否かとは独立である．
起きた人は必ずすべての知っている連絡先にモーニングコールをすること，また，モーニングコールを受けた人は必ず起きることを仮定するとき，全員がきちんと起きられる確率をこれらの情報から計算せよ．

Input

入力は複数のデータセットからなる． 各データセットは次の形式で表される．

N
p1 m1 a(1,1) ... a(1, m1)
...
pN mN a(N,1) ... a(N, mN)

N は参加者の数であり，100 を越えない正の整数である．pi は i 番目の参加者の寝坊する確率であり，小数点以下 2 桁以内の 0 以上 1 以下の実数である．mi は i 番目の参加者が知っている連絡先の数であり，0 以上 N 以下の整数である．a(i, j) は i 番目の参加者が知っている j 番目の連絡先が a(i, j) 番目の参加者のものであることを表す．a(i, j) は N を越えない正の整数である．

入力の終わりは，1 つのゼロからなる行で示す．

Output

各データセットについて，全員が起床できる確率を 1 行に出力せよ．出力には 0.00001 以上の誤差を含んではならない．

Sample Input

2
0.60 1 2
0.60 0
2
0.60 1 2
0.60 1 1
5
0.10 1 2
0.20 1 3
0.30 1 4
0.40 1 5
0.50 1 1
5
0.10 0
0.20 1 1
0.30 1 1
0.40 1 1
0.50 1 1
5
0.10 4 2 3 4 5
0.20 0
0.30 0
0.40 0
0.50 0
4
0.10 1 2
0.20 0
0.30 1 4
0.40 1 3
5
0.10 0
0.20 0
0.30 0
0.40 0
0.50 0
0

Output for Sample Input

0.400000000
0.640000000
0.998800000
0.168000000
0.900000000
0.792000000
0.151200000


Sample input:
2
0.60 1 2
0.60 0
2
0.60 1 2
0.60 1 1
5
0.10 1 2
0.20 1 3
0.30 1 4
0.40 1 5
0.50 1 1
5
0.10 0
0.20 1 1
0.30 1 1
0.40 1 1
0.50 1 1
5
0.10 4 2 3 4 5
0.20 0
0.30 0
0.40 0
0.50 0
4
0.10 1 2
0.20 0
0.30 1 4
0.40 1 3
5
0.10 0
0.20 0
0.30 0
0.40 0
0.50 0
0


Sample output:
0.400000000
0.640000000
0.998800000
0.168000000
0.900000000
0.792000000
0.151200000

Submission status: Wrong Answer

Solution code:
def fix(c):
  return int(c) - 1

def bfs(x, order, visited):
  if visited[x]:
    return
  visited[x] = True
  for to in edges[x]:
    bfs(to, order, visited)
  order.append(x)

def bfs_rev(x, visited):
  if visited[x]:
    return []
  visited[x] = True
  ret = [x]
  for to in rev_edges[x]:
    ret = ret + bfs_rev(to, visited)
  return ret

def bfs2(x, visited):
  if visited[x]:
    return
  visited[x] = True
  for to in edges[x]:
    bfs2(to, visited)

while True:
  n = int(input())
  if n == 0:
    break
  edges = []
  score = []
  for _ in range(n):
    lst = input().split()
    score.append(float(lst[0]))
    edges.append(list(map(fix, lst[2:])))
  rev_edges = [[] for _ in range(n)]
  for i in range(n):
    for e in edges[i]:
      rev_edges[e].append(i)
  
  #帰りがけ順取得
  visited = [False] * n
  order = []
  for x in range(n):
    bfs(x, order, visited)
  order.reverse()
  
  #強連結成分分解
  visited = [False] * n
  cycles = []
  for x in order:
    if not visited[x]:
      cycle = bfs_rev(x, visited)
      cycles.append(cycle)

  visited = [False] * n
  ans = 1
  for x in order:
    if not visited[x]:
      for cycle in cycles:
        if x in cycle:
          acc = 1
          for node in cycle:
            bfs2(node, visited)
            acc *= score[node]
          ans *= (1 - acc)

  print(ans)

Submission status: Accepted

Solution code:
def fix(c):
  return int(c) - 1

def bfs(x, order, visited):
  if visited[x]:
    return
  visited[x] = True
  for to in edges[x]:
    bfs(to, order, visited)
  order.append(x)

def bfs_rev(x, visited):
  if visited[x]:
    return []
  visited[x] = True
  ret = [x]
  for to in rev_edges[x]:
    ret = ret + bfs_rev(to, visited)
  return ret

def bfs2(x, visited):
  if visited[x]:
    return
  visited[x] = True
  for to in edges[x]:
    bfs2(to, visited)

while True:
  n = int(input())
  if n == 0:
    break
  edges = []
  score = []
  for _ in range(n):
    lst = input().split()
    score.append(float(lst[0]))
    edges.append(list(map(fix, lst[2:])))
  rev_edges = [[] for _ in range(n)]
  for i in range(n):
    for e in edges[i]:
      rev_edges[e].append(i)
  
  #帰りがけ順取得
  visited = [False] * n
  order = []
  for x in range(n):
    bfs(x, order, visited)
  order.reverse()
  
  #強連結成分分解
  visited = [False] * n
  cycles = []
  for x in order:
    if not visited[x]:
      cycle = bfs_rev(x, visited)
      cycles.append(cycle)

  visited = [False] * n
  ans = 1
  for x in order:
    if not visited[x]:
      for cycle in cycles:
        if x in cycle:
          acc = 1
          for node in cycle:
            bfs2(node, visited)
            acc *= score[node]
          ans *= (1 - acc)
  print("{0:.7f}".format(ans))

Submission status: Accepted

Solution code:

def dfs(s):
    for t in G[s]:
        if not used[t]:
            used[t] = 1
            dfs(t)
    res.append(s)
def rdfs(s, l):
    for t in RG[s]:
        if label[t] is None:
            label[t] = l
            rdfs(t, l)

while 1:
    n = int(input())
    if n == 0:
        break
    G = [[] for i in range(n)]
    RG = [[] for i in range(n)]
    P = []
    for i in range(n):
        p, m, *A = input().split()
        P.append(float(p))
        for t in map(int, A):
            G[i].append(t-1)
            RG[t-1].append(i)
    used = [0]*n
    res = []
    for i in range(n):
        if not used[i]:
            used[i] = 1
            dfs(i)
    label = [None]*n; k = 0
    for i in reversed(res):
        if label[i] is None:
            label[i] = k
            rdfs(i, k)
            k += 1
    GP = [1.]*k; GF = [0]*k
    for s in range(n):
        l = label[s]
        GP[l] *= P[s]
        for t in G[s]:
            if label[s] != label[t]:
                GF[label[t]] += 1
    ans = 1.
    for i in range(k):
        if GF[i] == 0:
            ans *= 1.-GP[i]
    print("%.9f" % (ans))