結果

問題 No.298 話の伝達
ユーザー qwewe
提出日時 2025-05-14 13:04:08
言語 PyPy3
(7.3.15)
結果
WA  
実行時間 -
コード長 6,121 bytes
コンパイル時間 345 ms
コンパイル使用メモリ 82,344 KB
実行使用メモリ 140,872 KB
最終ジャッジ日時 2025-05-14 13:06:01
合計ジャッジ時間 8,098 ms
ジャッジサーバーID
(参考情報)
judge2 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 15 WA * 1 TLE * 1 -- * 4
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

# Increase recursion depth limit. The maximum recursion depth could potentially be N,
# although typical depth might be related to the longest path in the DAG.
# Setting it to a value somewhat larger than N should be safe.
# N <= 20, so 20*2 = 40 is small. Let's set it higher for safety margin.
try:
    sys.setrecursionlimit(2050) 
except OverflowError: # Some systems might have a hard limit
     pass


# Read N, M from input
N, M = map(int, sys.stdin.readline().split())

# Create an adjacency list representation for predecessors.
# `adj[B]` will store a list of tuples `(A, P)`, where A is a predecessor of B, 
# and P is the probability (C/100.0) of transmission from A to B.
adj = {} 
for i in range(N):
    adj[i] = []  # Initialize empty list for each node 0 to N-1

# Read M relationships and populate the adjacency list
for _ in range(M):
    A, B, C = map(int, sys.stdin.readline().split())
    # The problem guarantees A != B.
    # Store predecessor A and its transmission probability C/100.0 for node B.
    adj[B].append((A, C / 100.0))

# Memoization table (cache) to store computed probabilities P(S).
# Keys are integer bitmasks representing subsets S. Values are the computed probabilities.
memo = {}

# Define the recursive function to compute P(S), the probability that *all* nodes 
# in the set S start talking about the topic.
# S is represented by an integer bitmask `mask`.
def compute_P(mask):
    """
    Computes the probability that all nodes specified by the set bits in 'mask'
    eventually start talking about the topic. Uses recursion with memoization.
    P(S) = P(intersection_{v in S} S_v) where S_v is the event node v starts talking.
    """
    
    # Base case 1: P(emptyset) = 1.0. The intersection over an empty set of events is the whole sample space.
    # This is important for the recursion logic when mask_without_k becomes 0.
    if mask == 0: 
        return 1.0
    
    # Base case 2: P({0}) = 1.0. Group 0 starts the conversation by definition.
    # The mask `1` represents the set {0}.
    if mask == 1: 
         return 1.0

    # Check if the result for this mask is already computed and stored in the memo table.
    if mask in memo:
        return memo[mask]

    # Identify the node 'k' with the highest index among nodes in the set S represented by 'mask'.
    # `mask.bit_length() - 1` gives the index of the most significant bit set in the mask.
    k = mask.bit_length() - 1
    
    # Retrieve the list of predecessors for node k from the adjacency list.
    # Use adj.get(k, []) to safely handle cases where k might not be in adj keys (though it should be).
    predecessors = adj.get(k, [])
    
    # If node k is not node 0 (i.e., k > 0) and has no predecessors, it can never start talking.
    # Therefore, the probability P(S) that all nodes in S (including k) start talking must be 0.
    # Note: Since mask > 1, k must be > 0 in this function body after base cases.
    if not predecessors: 
         memo[mask] = 0.0
         return 0.0

    # Calculate the mask representing the set S \ {k}.
    # This is done by flipping the k-th bit using XOR operation.
    mask_without_k = mask ^ (1 << k)

    # Initialize the total probability for the current calculation using Inclusion-Exclusion Principle.
    total_prob = 0.0
    
    num_preds = len(predecessors)
    # Iterate through all non-empty subsets J of the predecessors of k.
    # A subset J is represented by an integer 'i' from 1 to 2^num_preds - 1.
    # Each bit in 'i' corresponds to a predecessor in the `predecessors` list.
    for i in range(1, 1 << num_preds):
        # Calculate the product of transmission probabilities for predecessors in the current subset J.
        current_J_prob_product = 1.0
        # Determine the mask for the recursive call: It starts with S \ {k}.
        recursive_mask = mask_without_k
        
        subset_J_size = 0 # Keep track of the size of the subset J, |J|.
        
        # Iterate through the indices of the predecessors list to check which ones are in J.
        for j_idx in range(num_preds):
            # Check if the j_idx-th predecessor is included in subset J (check j_idx-th bit of i).
            if (i >> j_idx) & 1: 
                pred_node, pred_prob = predecessors[j_idx]
                # Multiply the probabilities for this edge into the product for J.
                current_J_prob_product *= pred_prob
                # Add the predecessor node `pred_node` to the set required for the recursive call.
                # The recursive call needs P(S \ {k} U A_J), where A_J = {pred_node | j_idx-th pred is in J}.
                # Set the corresponding bit for `pred_node` in `recursive_mask`.
                recursive_mask |= (1 << pred_node) 
                subset_J_size += 1 # Increment the size of J.
        
        # Make the recursive call to compute P(S \ {k} U A_J).
        # Multiply by the product of probabilities for transmissions from A_J to k.
        term = compute_P(recursive_mask) * current_J_prob_product
        
        # Apply the sign according to the Inclusion-Exclusion Principle based on the size of J.
        # If |J| is odd, the term has a positive sign (+).
        # If |J| is even, the term has a negative sign (-).
        if subset_J_size % 2 == 1: 
            total_prob += term
        else: 
            total_prob -= term

    # Store the computed probability for the current mask `mask` in the memo table.
    memo[mask] = total_prob
    # Return the computed probability.
    return total_prob

# Handle the trivial case where N=1. The only group is 0.
# It starts talking with probability 1, and it is also the target group N-1.
if N == 1:
     print(f"{1.0:.10f}")
else:
     # The target is group N-1. We need to compute P({N-1}).
     # The mask representing the set {N-1} is 1 shifted left by (N-1).
     target_mask = 1 << (N - 1)
     # Call the function to compute the probability for the target set {N-1}.
     result = compute_P(target_mask)
     # Print the final result formatted to 10 decimal places as required.
     print(f"{result:.10f}")
0