깊이우선탐색을 어떤 문제에 어떻게 적용하는지에 대해서 배우게 됩니다.
특정 정점(노드)에서 시작하여 갈 수 있는 곳까지 쭉 따라 들어갔다가 더 이상 갈 곳이 없으면 빠져나오는 방식의 그래프 탐색 방법
재귀함수 이용
⇒ 정점의 개수만큼의 크기를 갖는 visited 리스트를 만들어 방문한 위치와 방문하지 않은 위치 저장해야 한다.
DFS 함수를 호출하기 전에 해당 위치의 visited 값을 True로 변경한다.
# 노드 수, 간선 수
n, m = map(int, input().split())
# 인접 리스트
graph = [[] for _ in range(n + 1)]
for _ in range(m):
x, y = map(int, input().split())
# 양방향이므로 서로 넣어준다.
graph[x].append(y)
graph[y].append(x)
# 방문 리스트
visited = [False for _ in range(n + 1)]
def dfs(v):
global cnt
for i in graph[v]:
if not visited[i]:
# 1번 정점은 제외
if i != 1:
cnt += 1
visited[i] = True
dfs(i)
cnt = 0
dfs(1)
print(cnt)
처음에 1번 정점을 방문했다고 저장하면 정점마다 1번인지 아닌지 확인하지 않아도 된다.
DFS 함수에서는 현재 위치 (x, y)로부터 갈 수 있는 곳들을 전부 탐색, 갈 수 있다면 해당 위치를 방문 처리한 뒤 재귀함수 다시 호출
n, m = map(int, input().split())
grid = [list(map(int, input().split())) for _ in range(n)]
visited = [[0] * m for _ in range(n)]
def in_range(x, y):
return 0 <= x and x < n and 0 <= y and y < m
# 갈 수 있는 좌표인지 확인
def can_go(x, y):
# 다음 좌표가 격자 안에 있는지 확인
if not in_range(x, y):
return False
# 이미 방문했거나 뱀이 있는지 확인
if visited[x][y] or grid[x][y] == 0:
return False
return True
def dfs(x, y):
# 아래, 오른쪽
dxs, dys = [1, 0], [0, 1]
for dx, dy in zip(dxs, dys):
# 다음 좌표
new_x, new_y = x + dx, y + dy
# 갈 수 있는 곳이면 방문 처리 후 재귀함수 실행
if can_go(new_x, new_y):
visited[new_x][new_y] = 1
dfs(new_x, new_y)
dfs(0, 0)
# 끝지점 방문했다면 1 출력, 아니면 0 출력
if visited[n - 1][m - 1]:
print(1)
else:
print(0)
visited[0][0] = 1
추가해야 한다.n = int(input())
people = [list(map(int, input().split())) for _ in range(n)]
visited = [[0] * n for _ in range(n)]
# 마을 내 사람 수
cnt = 0
# 사람 수 리스트
residents = []
def in_range(x, y):
return 0 <= x and x < n and 0 <= y and y < n
def can_go(x, y):
if not in_range(x, y):
return False
if visited[x][y] or people[x][y] == 0:
return False
return True
def dfs(x, y):
global cnt
# 상, 하, 좌, 우
dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
for dx, dy in zip(dxs, dys):
nx, ny = x + dx, y + dy
if can_go(nx, ny):
visited[nx][ny] = 1
cnt += 1
dfs(nx, ny)
for i in range(n):
for j in range(n):
# 위치를 방문할 수 있다면
if can_go(i, j):
# 방문 여부 갱신
visited[i][j] = 1
# 새로운 마을 탐색한다는 의미로 cnt를 1로 갱신
cnt = 1
dfs(i, j)
# 한 마을 탐색 후 마을 내 사람 수 저장
residents.append(cnt)
# 마을 수 = 각 마을 내 사람 수 리스트 길이
print(len(residents))
# 각 마을 내 사람 수 오름차순 정렬
residents.sort()
for r in residents:
print(r)
마을과 같이 연결되어 있는 부분을 여러 개 찾을 때는 반복문을 사용하여 탐색을 여러 번 시행해준다.
import sys
sys.setrecursionlimit(2500)
n, m = map(int, input().split())
houses = [list(map(int, input().split())) for _ in range(n)]
# k의 최댓값 = 집 높이의 최댓값
max_k = max(max(houses))
def in_range(x, y):
return 0 <= x and x < n and 0 <= y and y < m
def can_go(x, y, k):
# 격자를 벗어나면 False
if not in_range(x, y):
return False
# 집 높이가 k보다 작거나 같으면 또는 이미 방문한 위치면 False
if houses[x][y] <= k or visited[x][y]:
return False
return True
def dfs(x, y, k):
# 상, 하, 좌, 우
dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
for dx, dy in zip(dxs, dys):
nx, ny = x + dx, y + dy
if can_go(nx, ny, k):
visited[nx][ny] = 1
dfs(nx, ny, k)
max_area = 0
ans_k = 1
for k in range(1, max_k + 1):
num_of_area = 0
visited = [[0] * m for _ in range(n)]
for i in range(n):
for j in range(m):
# 갈 수 있는 좌표면 방문 표시
if can_go(i, j, k):
visited[i][j] = 1
num_of_area += 1
dfs(i, j, k)
# 현재 최대 영역의 수보다 큰 경우 갱신
if max_area < num_of_area:
max_area, ans_k = num_of_area, k
print(ans_k, max_area)
재귀함수가 너무 깊게 들어가면 Error가 발생하므로 최대로 들어갈 깊이를 계산하여 sys.setrecursionlimit(최대로 들어갈 깊이)
을 설정해주어야 한다.
n = int(input())
grid = [list(map(int, input().split())) for _ in range(n)]
visited = [[0] * n for _ in range(n)]
# 격자 벗어나는지 확인
def in_range(x, y):
return 0 <= x and x < n and 0 <= y and y < n
# 갈 수 있는 위치인지 확인
def can_go(x, y):
if not in_range(x, y):
return False
if visited[x][y]:
return False
return True
def dfs(x, y):
global block_cnt
# 상, 하, 좌, 우
dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
for dx, dy in zip(dxs, dys):
nx, ny = x + dx, y + dy
# 갈 수 있는 위치이고, 다음 숫자가 같은 숫자인 경우 방문
if can_go(nx, ny) and grid[nx][ny] == grid[x][y]:
visited[nx][ny] = 1
block_cnt += 1
dfs(nx, ny)
boom = 0
max_block_cnt = 0
for i in range(n):
for j in range(n):
# 새로운 블럭 탐색
block_cnt = 1
if can_go(i, j):
visited[i][j] = 1
dfs(i, j)
# 블럭의 수가 4개 이상인 경우 터지는 블럭 수 1 증가
if block_cnt >= 4:
boom += 1
# 현재 블럭의 수가 기존의 최대 블럭의 수보다 클 경우 갱신
if max_block_cnt < block_cnt:
max_block_cnt = block_cnt
print(boom, max_block_cnt)