from collections import deque
# Define the possible connections for each pipe type
pipe_connections = {
'═': {'left': (0, -1), 'right': (0, 1)},
'║': {'up': (-1, 0), 'down': (1, 0)},
'╔': {'right': (0, 1), 'down': (1, 0)},
'╗': {'left': (0, -1), 'down': (1, 0)},
'╚': {'right': (0, 1), 'up': (-1, 0)},
'╝': {'left': (0, -1), 'up': (-1, 0)},
'╠': {'right': (0, 1), 'down': (1, 0), 'up': (-1, 0)},
'╣': {'left': (0, -1), 'down': (1, 0), 'up': (-1, 0)},
'╦': {'left': (0, -1), 'right': (0, 1), 'down': (1, 0)},
'╩': {'left': (0, -1), 'right': (0, 1), 'up': (-1, 0)}
}
# Define reverse connections for bidirectional checking
reverse_directions = {
'left': 'right',
'right': 'left',
'up': 'down',
'down': 'up'
}
# Helper function to get all valid neighbors based on pipe type and connectivity
def get_neighbors(grid, row, col):
neighbors = []
cell = grid[row][col]
if cell in pipe_connections:
for direction, (dr, dc) in pipe_connections[cell].items():
nr, nc = row + dr, col + dc
if 0 <= nr < len(grid) and 0 <= nc < len(grid[0]):
neighbor_cell = grid[nr][nc]
if neighbor_cell == '*' or neighbor_cell.isupper():
neighbors.append((nr, nc))
elif neighbor_cell in pipe_connections:
if reverse_directions[direction] in pipe_connections[neighbor_cell]:
neighbors.append((nr, nc))
return neighbors
def is_connected(grid, start):
rows, cols = len(grid), len(grid[0])
queue = deque([start])
visited = set([start])
connected_sinks = set()
while queue:
r, c = queue.popleft()
for nr, nc in get_neighbors(grid, r, c):
if (nr, nc) not in visited:
visited.add((nr, nc))
queue.append((nr, nc))
if grid[nr][nc].isupper():
connected_sinks.add(grid[nr][nc])
return connected_sinks
def find_connected_sinks(grid):
# Locate the source
start = None
for r in range(len(grid)):
for c in range(len(grid[0])):
if grid[r][c] == '*':
start = (r, c)
break
if start:
break
if not start:
return set() # No source found
return is_connected(grid, start)
# Example usage
ZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgZGVxdWUKCiMgRGVmaW5lIHRoZSBwb3NzaWJsZSBjb25uZWN0aW9ucyBmb3IgZWFjaCBwaXBlIHR5cGUKcGlwZV9jb25uZWN0aW9ucyA9IHsKICAgICfilZAnOiB7J2xlZnQnOiAoMCwgLTEpLCAncmlnaHQnOiAoMCwgMSl9LAogICAgJ+KVkSc6IHsndXAnOiAoLTEsIDApLCAnZG93bic6ICgxLCAwKX0sCiAgICAn4pWUJzogeydyaWdodCc6ICgwLCAxKSwgJ2Rvd24nOiAoMSwgMCl9LAogICAgJ+KVlyc6IHsnbGVmdCc6ICgwLCAtMSksICdkb3duJzogKDEsIDApfSwKICAgICfilZonOiB7J3JpZ2h0JzogKDAsIDEpLCAndXAnOiAoLTEsIDApfSwKICAgICfilZ0nOiB7J2xlZnQnOiAoMCwgLTEpLCAndXAnOiAoLTEsIDApfSwKICAgICfilaAnOiB7J3JpZ2h0JzogKDAsIDEpLCAnZG93bic6ICgxLCAwKSwgJ3VwJzogKC0xLCAwKX0sCiAgICAn4pWjJzogeydsZWZ0JzogKDAsIC0xKSwgJ2Rvd24nOiAoMSwgMCksICd1cCc6ICgtMSwgMCl9LAogICAgJ+KVpic6IHsnbGVmdCc6ICgwLCAtMSksICdyaWdodCc6ICgwLCAxKSwgJ2Rvd24nOiAoMSwgMCl9LAogICAgJ+KVqSc6IHsnbGVmdCc6ICgwLCAtMSksICdyaWdodCc6ICgwLCAxKSwgJ3VwJzogKC0xLCAwKX0KfQoKIyBEZWZpbmUgcmV2ZXJzZSBjb25uZWN0aW9ucyBmb3IgYmlkaXJlY3Rpb25hbCBjaGVja2luZwpyZXZlcnNlX2RpcmVjdGlvbnMgPSB7CiAgICAnbGVmdCc6ICdyaWdodCcsCiAgICAncmlnaHQnOiAnbGVmdCcsCiAgICAndXAnOiAnZG93bicsCiAgICAnZG93bic6ICd1cCcKfQoKIyBIZWxwZXIgZnVuY3Rpb24gdG8gZ2V0IGFsbCB2YWxpZCBuZWlnaGJvcnMgYmFzZWQgb24gcGlwZSB0eXBlIGFuZCBjb25uZWN0aXZpdHkKZGVmIGdldF9uZWlnaGJvcnMoZ3JpZCwgcm93LCBjb2wpOgogICAgbmVpZ2hib3JzID0gW10KICAgIGNlbGwgPSBncmlkW3Jvd11bY29sXQogICAgaWYgY2VsbCBpbiBwaXBlX2Nvbm5lY3Rpb25zOgogICAgICAgIGZvciBkaXJlY3Rpb24sIChkciwgZGMpIGluIHBpcGVfY29ubmVjdGlvbnNbY2VsbF0uaXRlbXMoKToKICAgICAgICAgICAgbnIsIG5jID0gcm93ICsgZHIsIGNvbCArIGRjCiAgICAgICAgICAgIGlmIDAgPD0gbnIgPCBsZW4oZ3JpZCkgYW5kIDAgPD0gbmMgPCBsZW4oZ3JpZFswXSk6CiAgICAgICAgICAgICAgICBuZWlnaGJvcl9jZWxsID0gZ3JpZFtucl1bbmNdCiAgICAgICAgICAgICAgICBpZiBuZWlnaGJvcl9jZWxsID09ICcqJyBvciBuZWlnaGJvcl9jZWxsLmlzdXBwZXIoKToKICAgICAgICAgICAgICAgICAgICBuZWlnaGJvcnMuYXBwZW5kKChuciwgbmMpKQogICAgICAgICAgICAgICAgZWxpZiBuZWlnaGJvcl9jZWxsIGluIHBpcGVfY29ubmVjdGlvbnM6CiAgICAgICAgICAgICAgICAgICAgaWYgcmV2ZXJzZV9kaXJlY3Rpb25zW2RpcmVjdGlvbl0gaW4gcGlwZV9jb25uZWN0aW9uc1tuZWlnaGJvcl9jZWxsXToKICAgICAgICAgICAgICAgICAgICAgICAgbmVpZ2hib3JzLmFwcGVuZCgobnIsIG5jKSkKICAgIHJldHVybiBuZWlnaGJvcnMKCmRlZiBpc19jb25uZWN0ZWQoZ3JpZCwgc3RhcnQpOgogICAgcm93cywgY29scyA9IGxlbihncmlkKSwgbGVuKGdyaWRbMF0pCiAgICBxdWV1ZSA9IGRlcXVlKFtzdGFydF0pCiAgICB2aXNpdGVkID0gc2V0KFtzdGFydF0pCiAgICBjb25uZWN0ZWRfc2lua3MgPSBzZXQoKQogICAgCiAgICB3aGlsZSBxdWV1ZToKICAgICAgICByLCBjID0gcXVldWUucG9wbGVmdCgpCiAgICAgICAgZm9yIG5yLCBuYyBpbiBnZXRfbmVpZ2hib3JzKGdyaWQsIHIsIGMpOgogICAgICAgICAgICBpZiAobnIsIG5jKSBub3QgaW4gdmlzaXRlZDoKICAgICAgICAgICAgICAgIHZpc2l0ZWQuYWRkKChuciwgbmMpKQogICAgICAgICAgICAgICAgcXVldWUuYXBwZW5kKChuciwgbmMpKQogICAgICAgICAgICAgICAgaWYgZ3JpZFtucl1bbmNdLmlzdXBwZXIoKToKICAgICAgICAgICAgICAgICAgICBjb25uZWN0ZWRfc2lua3MuYWRkKGdyaWRbbnJdW25jXSkKICAgIAogICAgcmV0dXJuIGNvbm5lY3RlZF9zaW5rcwoKZGVmIGZpbmRfY29ubmVjdGVkX3NpbmtzKGdyaWQpOgogICAgIyBMb2NhdGUgdGhlIHNvdXJjZQogICAgc3RhcnQgPSBOb25lCiAgICBmb3IgciBpbiByYW5nZShsZW4oZ3JpZCkpOgogICAgICAgIGZvciBjIGluIHJhbmdlKGxlbihncmlkWzBdKSk6CiAgICAgICAgICAgIGlmIGdyaWRbcl1bY10gPT0gJyonOgogICAgICAgICAgICAgICAgc3RhcnQgPSAociwgYykKICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgaWYgc3RhcnQ6CiAgICAgICAgICAgIGJyZWFrCiAgICAKICAgIGlmIG5vdCBzdGFydDoKICAgICAgICByZXR1cm4gc2V0KCkgICMgTm8gc291cmNlIGZvdW5kCiAgICAKICAgIHJldHVybiBpc19jb25uZWN0ZWQoZ3JpZCwgc3RhcnQpCgojIEV4YW1wbGUgdXNhZ2UK