結果

問題 No.1776 Love Triangle 2 (Hard)
ユーザー qwewe
提出日時 2025-05-14 12:56:18
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 6,853 bytes
コンパイル時間 416 ms
コンパイル使用メモリ 82,780 KB
実行使用メモリ 85,868 KB
最終ジャッジ日時 2025-05-14 12:58:47
合計ジャッジ時間 12,734 ms
ジャッジサーバーID
(参考情報)
judge2 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 4 TLE * 1 -- * 171
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

# Increase recursion depth limit for deep searches that might occur with path lengths up to N.
# N can be up to 150. Setting limit to N + buffer, e.g., 200 or higher.
# Using 2000 as a safe large value.
try:
    sys.setrecursionlimit(2000) 
except Exception as e:
    # Some platforms might restrict changing recursion depth. Proceed anyway.
    # Might raise RecursionError if path length exceeds default limit.
    # print(f"Warning: Could not set recursion depth: {e}", file=sys.stderr)
    pass

def solve():
    # Read N (number of students) and M (number of friendships)
    N, M = map(int, sys.stdin.readline().split())
    
    # Read the three special students X, Y, Z
    X, Y, Z = map(int, sys.stdin.readline().split())
    
    # Initialize adjacency matrix for the friendship graph G.
    # adj[u][v] = True if u and v are friends.
    # Size (N+1)x(N+1) to use 1-based indexing conveniently.
    adj = [[False] * (N + 1) for _ in range(N + 1)]
    for _ in range(M):
        u, v = map(int, sys.stdin.readline().split())
        adj[u][v] = True
        adj[v][u] = True # Friendships are mutual (undirected graph)

    # Precompute the adjacency list for the complement graph G_bar.
    # An edge (u, v) exists in G_bar if u and v are NOT friends.
    # Store neighbors for each node in a list.
    non_friend_adj = [[] for _ in range(N + 1)]
    for i in range(1, N + 1):
        for j in range(1, N + 1):
             # Check if i and j are different nodes and are not friends
             if i != j and not adj[i][j]:
                 non_friend_adj[i].append(j)
    
    # Sort the neighbor lists for G_bar. This is crucial for ensuring that
    # when we explore paths, we do so in an order that guarantees finding
    # the lexicographically smallest path first.
    for i in range(1, N + 1):
        non_friend_adj[i].sort()

    # Variables to store the result: minimum cycle length k and the path itself.
    best_k = -1
    best_path = []

    # State variables for the Depth First Search (DFS)
    visited = [False] * (N + 1) # Keep track of nodes visited in the current path
    path = [] # Store the nodes in the current path being explored

    # Recursive DFS function to find a cycle of a specific length k_target
    def find_cycle_recursive(curr_node, k_target):
        # Declare that we intend to modify these variables defined in the outer scope
        nonlocal best_k, best_path 
        
        # Add the current node to the path and mark it as visited
        path.append(curr_node)
        visited[curr_node] = True
        
        current_len = len(path)

        # Base Case: If the path length reaches the target length k_target
        if current_len == k_target:
            # Check two conditions for a valid cycle:
            # 1. The last node in the path (curr_node) must be able to connect back to the starting node X.
            #    This means curr_node and X must NOT be friends (edge exists in G_bar).
            # 2. The required students Y and Z must be included in the path.
            
            # Check connection back to X
            if not adj[curr_node][X]: 
                # Check inclusion of Y and Z using the visited array (efficient)
                if visited[Y] and visited[Z]: 
                    # Found a valid cycle that satisfies all conditions!
                    best_k = k_target
                    # Construct the final path representation: start node X, followed by path nodes, ending with X.
                    # The 'path' list currently contains nodes from X up to curr_node.
                    # We need to copy it and append X at the end for the output format.
                    best_path = path[:] + [X] 
                    
                    # Backtrack state correctly before returning True to signal success
                    visited[curr_node] = False
                    path.pop()
                    return True # Cycle found
            
            # If either condition fails (cannot connect back to X, or Y/Z missing), backtrack state
            visited[curr_node] = False
            path.pop()
            return False # Cycle not valid or incomplete, continue search

        # Recursive Step: Explore neighbors of the current node
        # Iterate through neighbors in the complement graph G_bar
        # The neighbors list is already sorted, ensuring lexicographical exploration
        for next_node in non_friend_adj[curr_node]:
            # Explore neighbor only if it has not been visited in the current path
            # This prevents cycles within the path (ensures simple path)
            if not visited[next_node]:
                 # Make the recursive call for the neighbor
                 if find_cycle_recursive(next_node, k_target):
                     # If the recursive call returns True, it means a cycle was found down that path.
                     # We need to propagate this True result upwards.
                     # Important: Backtrack the state of the current node before returning.
                     visited[curr_node] = False 
                     path.pop() 
                     return True # Signal cycle found
        
        # If no cycle was found through any neighbor of curr_node, backtrack state
        visited[curr_node] = False
        path.pop()
        return False # No cycle found from this path branch

    # Main part of the algorithm: Iterate through possible cycle lengths k
    # Start from k=3 (minimum possible cycle length) up to N (maximum possible).
    for k in range(3, N + 1):
        # Reset the visited array and path list for the search with the new length k
        # Clearing the visited array directly is faster than creating a new one each time.
        for i in range(1, N + 1):
             visited[i] = False
        path = [] # Reset the path list
        
        # Start the DFS search from the designated starting node X
        if find_cycle_recursive(X, k):
             # If find_cycle_recursive returns True, it means a cycle of length k was found.
             # Since we iterate k in increasing order, the first k for which we find a cycle is the minimum k.
             # And because we explore neighbors in sorted order, the first cycle found for this minimum k
             # is guaranteed to be the lexicographically smallest one.
             # Therefore, we can stop the search immediately.
             break 

    # After checking all possible lengths k, output the result.
    if best_k != -1:
        # A valid cycle was found
        print(best_k) # Output the minimum length k
        print(*(best_path)) # Output the lexicographically smallest path (nodes separated by spaces)
    else:
        # No valid cycle was found for any length k
        print("-1")

# Execute the main function to solve the problem
solve()
0