from collections import deque from itertools import product def get_neighbours(i, j, r, c): """Returns valid neighbouring cells of (i,j)""" neighbours = [] if i > 0: neighbours.append((i-1, j)) # North if i < r-1: neighbours.append((i+1, j)) # South if j > 0: neighbours.append((i, j-1)) # West if j < c-1: neighbours.append((i, j+1)) # East return neighbours def find_drivable_pairs(grid, starts, finishes): """Finds all drivable pairs of start and finish cells""" r, c = len(grid), len(grid[0]) # Create a graph where each cell is a node and each edge represents a valid move graph = {(i, j): [] for i, j in product(range(r), range(c))} for i, row in enumerate(grid): for j, cell in enumerate(row): if cell != '#': # ignore walls for ni, nj in get_neighbours(i, j, r, c): if grid[ni][nj] != '#': graph[(i, j)].append((ni, nj)) # Perform BFS from each start cell to calculate probability of reaching each cell prob = {start: {cell: 0.0 for cell in graph} for start in starts} for start in starts: visited = set([start]) queue = deque([(start, 1.0)]) while queue: node, p = queue.popleft() for neighbour in graph[node]: if neighbour not in visited: visited.add(neighbour) prob[start][neighbour] = p / len(graph[node]) queue.append((neighbour, p / len(graph[node]))) # Check which pairs of start and finish cells are drivable drivable_pairs = [] for start in starts: for finish in finishes: if prob[start][finish] >= 1.0 - 1e-100: drivable_pairs.append((start, finish)) return drivable_pairs # Main program T = int(input()) for t in range(1, T+1): R, C = map(int, input().split()) grid = [input() for _ in range(R)] starts = [] finishes = [] for i in range(R): for j in range(C): if grid[i][j].islower(): starts.append((i, j)) elif grid[i][j].isupper(): finishes.append((i, j)) drivable_pairs = find_drivable_pairs(grid, starts, finishes) print("Case #{}: {}".format(t, ' '.join([''.join(pair) for pair in sorted(drivable_pairs)])) if drivable_pairs else "Case #{}: NONE".format(t))