C - 洞窟探検 / Cave Exploration 解説 by admin 印刷ページ
Claude 4.6 Opus (Thinking)Overview
A simulation problem where you explore rooms in a cave following specific rules. It is a variant of Depth-First Search (DFS) with an additional movement condition: “the lighting color of the destination room must be different from the current room.”
Analysis
Essence of the Problem
This problem is a standard DFS (Depth-First Search) with the following special rules added: - Movement condition: The destination must be unvisited and its lighting color must differ from the current room - Same-color skip: Even if the destination is unvisited, if it has the same color, do not move there. However, do not mark it as visited either (it may be visited later from a different route) - Resumption after backtracking: After returning, resume checking from the next corridor after where you left off
Key Insight
The crucial point is that after backtracking, you “resume from the next corridor after where you left off.” In other words, the corridor list for each room has a structure where previously traversed portions are not checked again. This ensures each edge is checked at most once, allowing efficient simulation.
What About Naive Recursion?
If implemented with recursion, there is a risk of stack overflow since \(N\) can be up to \(2 \times 10^5\). An iterative implementation (managing the stack manually) is necessary.
Algorithm
Simulate the exploration using iterative DFS with an explicit stack.
- Push
(room number, index of the next edge to check)onto the stack - For the room at the top of the stack, check corridors starting from the edge index:
- Destination is visited → Skip (advance the index)
- Destination is unvisited but same color → Skip (advance the index, do not mark as visited)
- Destination is unvisited and different color → Mark as visited and move (push the new room onto the stack)
- If all corridors have been checked with no valid destination, pop from the stack (backtrack)
- When the stack becomes empty, the exploration is complete
Concrete example (\(N=4\), Room 1: red, Room 2: blue, Room 3: red, Room 4: blue, Edges: 1→3, 1→2, 2→4): - Room 1 (red): Check corridor 1→3 → Room 3 is red (same color) → Skip - Room 1 (red): Check corridor 1→2 → Room 2 is blue (different color) → Move! - Room 2 (blue): Check corridor 2→4 → Room 4 is blue (same color) → Skip - Room 2: No more corridors → Backtrack to Room 1 - Room 1: Resume from after corridor 1→2 → No more corridors → Exploration complete - Unvisited: Room 3, Room 4
Complexity
- Time complexity: \(O(N + M)\)
- Each edge is checked at most once (after backtracking, exploration resumes from the next position after the interruption, so the edge index never goes backward)
- Space complexity: \(O(N + M)\)
- \(O(N + M)\) for the adjacency list, at most \(O(N)\) for the stack
Implementation Notes
Store the edge index in each stack element: By updating as
stack[-1] = (room, ei), you can correctly resume from the right position after backtrackingIterative instead of recursive: Avoids Python’s default recursion limit and handles large inputs
Timing of
visited[v]checks: Corresponding to the problem statement’s “judge based on the state at that point,” thevisitedarray is referenced in real-time each time an edge is checkedAdvance
eion same-color skip: Unvisited rooms with the same color are skipped but not marked as visited, so they may be visited later from a different room’s exploration. However, they will not be checked again from the current room (because the index has advanced)Source Code
import sys
from sys import setrecursionlimit
def main():
input_data = sys.stdin.buffer.read().decode()
tokens = input_data.split()
idx = 0
N = int(tokens[idx]); idx += 1
M = int(tokens[idx]); idx += 1
C = [0] * (N + 1)
for i in range(1, N + 1):
C[i] = int(tokens[idx]); idx += 1
# adj[u] = list of v in order of priority (first given = highest priority)
adj = [[] for _ in range(N + 1)]
for j in range(M):
u = int(tokens[idx]); idx += 1
v = int(tokens[idx]); idx += 1
adj[u].append(v)
visited = [False] * (N + 1)
visited[1] = True
# Iterative DFS simulation
# Stack stores (room, edge_index)
# For each room on the stack, we process edges starting from edge_index
stack = [(1, 0)]
while stack:
room, ei = stack[-1]
edges = adj[room]
moved = False
while ei < len(edges):
v = edges[ei]
ei += 1 # next edge index for when we resume
if visited[v]:
# skip visited
continue
# v is unvisited
if C[v] == C[room]:
# same color, skip but don't mark visited
continue
else:
# different color, move to v
visited[v] = True
# Update current frame's edge index before pushing new frame
stack[-1] = (room, ei)
stack.append((v, 0))
moved = True
break
if not moved:
# All edges exhausted, backtrack
stack.pop()
unvisited = [i for i in range(1, N + 1) if not visited[i]]
if not unvisited:
print("COMPLETE")
else:
print(' '.join(map(str, unvisited)))
main()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: