오늘은 백준 31464번 초콜릿 괴도 코코 문제를 풀어보았다. 이 문제는 단일 덩어리로 연결된 초콜릿 중, 하나를 떼었을 때 여전히 연결된 상태를 유지하면서 단절점이 생기게 되는 칸들을 찾는 것이 목표였다.
핵심은 다음과 같다:
1. 특정 칸을 하나 제거한 뒤에도 전체가 연결되어 있어야 하고,
2. 그 상태에서 임의의 두 칸을 자르면 정확히 두 조각으로 나뉘어야 한다. (즉, 단절점이 존재해야 함)
그래서 다음 절차로 풀고자 했다:
어떤 문제가 있었고, 나는 어떤 시도를 했는지
어떻게 해결했는지
무엇을 새롭게 알았는지
내일 학습할 것은 무엇인지
import sys
N = int(input())
grid = [list(input().strip()) for _ in range(N)]
dirs = [(-1,0),(1,0),(0,-1),(0,1)]
def in_range(x, y):
return 0 <= x < N and 0 <= y < N
# dfs로 연결된 칸 수 세기
def dfs(x, y, visited, erased):
visited[x][y] = True
count = 1
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if in_range(nx, ny) and not visited[nx][ny] and grid[nx][ny] == '#' and (nx, ny) != erased:
count += dfs(nx, ny, visited, erased)
return count
# 단절점 찾기 (Tarjan 알고리즘)
def articulation_points(erased):
idx = [[-1]*N for _ in range(N)]
low = [[-1]*N for _ in range(N)]
visited = [[False]*N for _ in range(N)]
counter = [0]
result = set()
def dfs_ap(x, y, px, py, root):
visited[x][y] = True
idx[x][y] = low[x][y] = counter[0]
counter[0] += 1
children = 0
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if not in_range(nx, ny) or grid[nx][ny] != '#' or (nx, ny) == erased:
continue
if not visited[nx][ny]:
dfs_ap(nx, ny, x, y, False)
low[x][y] = min(low[x][y], low[nx][ny])
if not root and low[nx][ny] >= idx[x][y]:
result.add((x, y))
children += 1
elif (nx, ny) != (px, py):
low[x][y] = min(low[x][y], idx[nx][ny])
if root and children >= 2:
result.add((x, y))
for i in range(N):
for j in range(N):
if grid[i][j] == '#' and (i, j) != erased:
dfs_ap(i, j, -1, -1, True)
return result
return set()
# 전체 초콜릿 수 세기
total = sum(row.count('#') for row in grid)
answer = []
for i in range(N):
for j in range(N):
if grid[i][j] != '#':
continue
# 초콜릿을 떼어낸 후 연결 확인
visited = [[False]*N for _ in range(N)]
found = False
for x in range(N):
for y in range(N):
if grid[x][y] == '#' and (x, y) != (i, j):
size = dfs(x, y, visited, (i, j))
found = True
break
if found:
break
# 하나의 연결된 덩어리가 아니라면 스킵
connected = True
for x in range(N):
for y in range(N):
if grid[x][y] == '#' and (x, y) != (i, j) and not visited[x][y]:
connected = False
if not connected:
continue
# 단절점 검사
aps = articulation_points((i, j))
if aps:
answer.append((i + 1, j + 1))
# 출력
print(len(answer))
answer.sort()
for x, y in answer:
print(x, y)
#99클럽 #코딩테스트준비 #개발자취업 #항해99 #TIL