結果
| 問題 |
No.86 TVザッピング(2)
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 12:58:33 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 9,594 bytes |
| コンパイル時間 | 189 ms |
| コンパイル使用メモリ | 81,968 KB |
| 実行使用メモリ | 151,920 KB |
| 最終ジャッジ日時 | 2025-06-20 14:02:29 |
| 合計ジャッジ時間 | 8,118 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 WA * 1 |
| other | AC * 6 WA * 1 TLE * 1 -- * 22 |
ソースコード
import sys
# Increase recursion depth limit for potentially deep paths.
# The maximum path length (number of moves) is T, which can be up to N*M = 100*100 = 10000.
# The recursion depth can reach T. Setting it slightly above the maximum possible T.
try:
sys.setrecursionlimit(10500)
except OverflowError: # Handle potential OS limits on stack size
# If setting a high limit fails, use a default reasonable limit or warn.
# This might cause RecursionError on large test cases if the limit is too low.
# Let's just let it fail if the system cannot handle it. The competitive programming environment usually allows high limits.
pass
def solve():
N, M = map(int, sys.stdin.readline().split())
A = [sys.stdin.readline().strip() for _ in range(N)]
# Find all available cells (marked with '.')
available_cells = []
for r in range(N):
for c in range(M):
if A[r][c] == '.':
available_cells.append((r, c))
# Total number of available cells
T = len(available_cells)
# Based on graph theory (Hamiltonian cycle on bipartite graph) and problem rules analysis:
# 1. The number of available cells T must be even.
# 2. Analysis showed T=2 is impossible due to turn constraints.
# Therefore, T must be even and T >= 4 for a cycle to possibly exist.
if T % 2 != 0 or T < 4:
print("NO")
return
# Precompute adjacency list for available cells for efficiency.
# adj maps cell coordinates (tuple) to a list of adjacent available cell coordinates.
adj = {}
for r_idx in range(N):
for c_idx in range(M):
if A[r_idx][c_idx] == '.':
curr_cell = (r_idx, c_idx)
adj[curr_cell] = []
# Check potential neighbors in 4 cardinal directions
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]: # Right, Left, Down, Up
nr, nc = r_idx + dr, c_idx + dc
# Check if neighbor is within grid boundaries and is an available cell '.'
if 0 <= nr < N and 0 <= nc < M and A[nr][nc] == '.':
adj[curr_cell].append((nr, nc))
# Keep track of visited cells for the current DFS path. Use a 2D list for potentially better performance than dict.
visited = [[False for _ in range(M)] for _ in range(N)]
# Global variables to store context about the start of the path, needed for cycle closure checks.
start_cell_global = None # Stores the coordinates (tuple) of the starting cell for the current DFS attempt
first_move_dir_global = None # Stores the direction (dr, dc tuple) of the first move (v0 -> v1)
# Helper function to calculate the direction vector (dr, dc) from one cell to an adjacent cell.
def get_dir(from_cell, to_cell):
return (to_cell[0] - from_cell[0], to_cell[1] - from_cell[1])
# Helper function to calculate the direction resulting from a 90-degree left turn.
def left_turn(dr, dc):
# Rotation logic: (dr, dc) rotated left 90 degrees becomes (-dc, dr).
return (-dc, dr)
# Helper function to check if `curr_dir` is a valid next direction after `prev_dir`
# according to the problem rule: "straight or left turn".
def check_turn(prev_dir, curr_dir):
# Check if move is straight
if curr_dir == prev_dir:
return True
# Check if move is a left turn
lt_dir = left_turn(prev_dir[0], prev_dir[1])
if curr_dir == lt_dir:
return True
# If neither, the move direction is invalid by the rules
return False
# Depth First Search function to explore paths and check for a valid cycle.
# Parameters:
# curr_cell: The current cell coordinates (tuple).
# prev_cell: The coordinates of the cell visited just before curr_cell (tuple).
# visited_count: The number of distinct available cells visited so far in the current path.
def dfs(curr_cell, prev_cell, visited_count):
curr_r, curr_c = curr_cell
# Determine the direction of the move that arrived at curr_cell.
curr_dir = get_dir(prev_cell, curr_cell)
# Base Case: If T cells have been visited, check if path can close into a valid cycle.
if visited_count == T:
# Need to check if moving from curr_cell back to start_cell_global is possible and valid.
# 1. Adjacency Check: Is start_cell_global adjacent to curr_cell?
# Use Manhattan distance for grid adjacency check.
if abs(curr_r - start_cell_global[0]) + abs(curr_c - start_cell_global[1]) != 1:
return False # Not adjacent, cannot form cycle.
# 2. Calculate Final Move Direction: Determine direction for the move back to start.
final_dir = get_dir(curr_cell, start_cell_global)
# 3. Final Move Turn Rule Check: Does the final move (v_{T-1} -> v_0) follow the turn rule based on the previous move (v_{T-2} -> v_{T-1})?
# The direction of the move v_{T-2} -> v_{T-1} is stored in curr_dir.
if not check_turn(curr_dir, final_dir):
return False
# 4. First Move Turn Rule Check (Cycle Consistency): Does the first move (v_0 -> v_1) follow the turn rule based on the final move (v_{T-1} -> v_0)?
# This ensures the turn rule holds across the cycle wrap-around.
if not check_turn(final_dir, first_move_dir_global):
return False
# If all checks pass, we have found a valid cycle satisfying all conditions.
return True
# Recursive Step: Explore possible next moves from curr_cell.
# Mark current cell as visited for this path exploration.
visited[curr_r][curr_c] = True
# Calculate the two possible next directions according to the rules: straight or left turn.
straight_dir = curr_dir
left_turn_dir = left_turn(curr_dir[0], curr_dir[1])
# Try moving Straight
next_cell_S = (curr_r + straight_dir[0], curr_c + straight_dir[1])
# Check if the cell is within bounds and is an available cell ('.')
if 0 <= next_cell_S[0] < N and 0 <= next_cell_S[1] < M and A[next_cell_S[0]][next_cell_S[1]] == '.':
# Check if the cell hasn't been visited yet in the current path
if not visited[next_cell_S[0]][next_cell_S[1]]:
# Recursively call DFS for the next cell
if dfs(next_cell_S, curr_cell, visited_count + 1):
# If recursive call found a solution, propagate True up the call stack.
return True
# If the target is the start cell, it must be the final move to close the cycle.
# This logic is implicitly handled by the base case check when visited_count reaches T.
# The `not visited` check correctly prevents revisiting start_cell_global prematurely.
# Try moving Left Turn
next_cell_L = (curr_r + left_turn_dir[0], curr_c + left_turn_dir[1])
# Check if the cell is valid
if 0 <= next_cell_L[0] < N and 0 <= next_cell_L[1] < M and A[next_cell_L[0]][next_cell_L[1]] == '.':
# Check if the cell hasn't been visited yet
if not visited[next_cell_L[0]][next_cell_L[1]]:
# Recurse
if dfs(next_cell_L, curr_cell, visited_count + 1):
return True
# Similar implicit handling if next_cell_L is the start cell.
# Backtrack: If no path found from curr_cell, unmark it as visited.
# This allows other paths to potentially use this cell.
visited[curr_r][curr_c] = False
# Return False indicating no solution found from this state downwards.
return False
# Main loop to initiate DFS search attempts.
# Try starting the path from each available cell.
for r_start, c_start in available_cells:
start_cell = (r_start, c_start)
# A starting cell must have at least one neighbor to start a path.
# adj check handles isolated '.' cells, although problem guarantees T>=2.
if start_cell not in adj or not adj[start_cell]: continue
# Try each neighbor of the start cell as the target of the first move.
for first_neighbor in adj[start_cell]:
# Reset the visited state tracker for each new DFS attempt.
for r_vis in range(N):
for c_vis in range(M):
visited[r_vis][c_vis] = False
# Set the global context variables for this specific DFS run.
start_cell_global = start_cell
first_move_dir_global = get_dir(start_cell, first_neighbor)
# Mark the starting cell as visited before initiating DFS.
visited[r_start][c_start] = True
# Start the DFS from the first neighbor.
# The initial path has length 1 (1 move), involves 2 cells (start and first neighbor).
# So, visited_count starts at 2.
if dfs(first_neighbor, start_cell, 2):
# If DFS returns True, a valid cycle path has been found.
print("YES")
return # Exit the function immediately.
# If the loops complete without finding any valid path from any start cell / first move combination.
print("NO")
# Call the main solve function to run the logic.
solve()
qwewe