[깊이 우선 탐색의 핵심 이론]
예시) 1 -> 2 -> 5
-> 6
1 -> 3 -> 4 -> 6
시간 제한 3초, 실버 V, 백준 11724번
방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오.
첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.
6 5 # 노드 개수, 에지 개수 1 2 2 5 5 1 3 4 4 6
첫째 줄에 연결 요소의 개수를 출력한다.
2
인접 리스트
1 -> 2 / 5
2 -> 1 / 5
3 -> 4
4 -> 3 / 6
5 -> 2 / 1
6 -> 4
방문 리스트
1 2 3 4 5 6
F F F F F F
방문 리스트
1 2 3 4 5 6
T T F F T F
탐색 순서: 1 -> 2 -> 5
방문 리스트
1 2 3 4 5 6
T T T T T T
탐색 순서: 1 -> 2 -> 5 -> 3 -> 4 -> 6 -> 종료
n(노드 개수) m(에지 개수)
A(그래프 데이터 저장 인접 리스트) 초기화
visited(방문 기록 리스트) 초기화
# DFS 구현
DFS:
visited 리스트에 현재 노드 방문 기록
현재 노드의 연결 노드 중 방문하지 않은 노드로 DFS 실행(재귀 함수 형태)
for m의 개수만큼 반복:
A 인접 리스트에 그래프 데이터 저장
for n의 개수만큼 반복:
if 방문하지 않은 노드가 있으면:
연결 요소 개수 값 1 증가
DFS 실행
연결 요소 개수 값 출력
import sys
sys.setrecursionlimit(10000) # 재귀 호출의 최대 깊이 제한을 설정하는 함수
input = sys.stdin.readline
n, m = map(int, input().split())
A = [[] for _ in range(n+1)]
visited = [False] * (n+1)
def DFS(v):
visited[v] = True
for i in A[v]: # ex) 1에 연결된 2와 5 모두 DFS 수행
if not visited[i]:
DFS(i)
for _ in range(m): # 그래프를 인접 리스트로 저장하기
s, e = map(int, input().split())
A[s].append(e) # 양방향 에지이므로 양쪽에 에지를 더하기
A[e].append(s)
count = 0
for i in range(1, n+1):
if not visited[i]:
count += 1
DFS(i)
print(count)
시간 제한 2초, 골드 V, 백준 2023번
수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다.
7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수이고, 7도 소수이다. 즉, 왼쪽부터 1자리, 2자리, 3자리, 4자리 수 모두 소수이다! 수빈이는 이런 숫자를 신기한 소수라고 이름 붙였다.
수빈이는 N자리의 숫자 중에서 어떤 수들이 신기한 소수인지 궁금해졌다. N이 주어졌을 때, 수빈이를 위해 N자리 신기한 소수를 모두 찾아보자.
첫째 줄에 N(1 ≤ N ≤ 8)이 주어진다.
4 # 자릿수 N
N자리 수 중에서 신기한 소수를 오름차순으로 정렬해서 한 줄에 하나씩 출력한다.
2333 2339 2393 2399 2939 3119 3137 3733 3739 3793 3797 5939 7193 7331 7333 7393
[문제 핵심]
N(자릿수)
#소수 구하기 함수
for i를 2~(현재 수/2)+1까지 반복:
if 현재 수 % i가 0이면:
return 소수가 아님
#DFS 구현
DFS(숫자):
if 자릿수 == N:
현재 수 출력
else
for i를 1~9 반복:
if i를 뒤에 붙인 새로운 수가 홀수이면서 소수일 때 # 소수 구하기 함수 사용
DFS(수 * 10 + 뒤에 붙는 수) 실행
DFS 실행(숫자 2, 3, 5, 7로 탐색 시작)
import sys
sys.setrecursionlimit(10000)
input = sys.stdin.readline
N = int(input())
def isPrime(num):
for i in range(2, int(num / 2 + 1)):
if num % i == 0:
return False
return True
def DFS(number):
if len(str(number)) == N:
print(number)
else:
for i in range(1, 10):
if i % 2 == 0: # 짝수라면 더는 탐색 불필요
continue
if isPrime(number * 10 + i): # 소수라면 자릿수 늘림
DFS(number * 10 + i)
# 일의 자리 소수는 2, 3, 5, 7이므로 4가지 수에서만 시작
DFS(2)
DFS(3)
DFS(5)
DFS(7)
시간 제한 2초, 골드 V, 백준 13023번
BOJ 알고리즘 캠프에는 총 N명이 참가하고 있다. 사람들은 0번부터 N-1번으로 번호가 매겨져 있고, 일부 사람들은 친구이다.
오늘은 다음과 같은 친구 관계를 가진 사람 A, B, C, D, E가 존재하는지 구해보려고 한다.
- A는 B와 친구다.
- B는 C와 친구다.
- C는 D와 친구다.
- D는 E와 친구다.
위와 같은 친구 관계가 존재하는지 안하는지 구하는 프로그램을 작성하시오.
첫째 줄에 사람의 수 N (5 ≤ N ≤ 2000)과 친구 관계의 수 M (1 ≤ M ≤ 2000)이 주어진다.
둘째 줄부터 M개의 줄에는 정수 a와 b가 주어지며, a와 b가 친구라는 뜻이다. (0 ≤ a, b ≤ N-1, a ≠ b) 같은 친구 관계가 두 번 이상 주어지는 경우는 없다.8 8 # 노드 개수, 에지 개수 1 7 3 7 4 7 3 4 4 6 3 5 0 4 2 7
문제의 조건에 맞는 A, B, C, D, E가 존재하면 1을 없으면 0을 출력한다.
1
모든 노드에서 DFS를 수행한다. 수행할 때 재귀 호출마다 깊이를 더한다. 깊이가 5가 되면 1을 출력하고 프로그램을 종료한다.
모든 노드를 돌아도 1이 출력되지 않았다면 0을 출력한다.
N(노드 개수) M(에지 개수)
A(그래프 데이터 저장 인접 리스트)
visited(방문 기록 저장 리스트)
arrive(도착 확인 변수)
# DFS 구현(현재 노드, 깊이):
if 깊이가 5:
arrive = true;
함수 종료
방문 리스트에 현재 노드 방문 기록
현재 노드의 연결 노드 중 방문하지 않은 노드로 DFS 실행 # 호출마다 depth는 1씩 증가
for M의 개수만큼 반복:
A 인접 리스트에 그래프 데이터 저장
for N의 개수만큼 반복:
노드마다 DFS 실행
if(arrive) 반복문 종료 # depth가 5에 도달한 적이 있다면
if arrive: 1 출력
else: 0 출력
import sys
sys.setrecursionlimit(10000)
input = sys.stdin.readline
N, M = map(int, input().split())
arrive = False
A = [[] for _ in range(N+1)]
visited = [False] * (N+1)
def DFS(now, depth):
global arrive
if depth == 5: # 깊이가 5가 되면 종료
arrive = True
return
visited[now] = True
for i in A[now]:
if not visited[i]:
DFS(i, depth + 1) # 재귀 호출마다 깊이 증가
visited[now] = False
for _ in range(M): # 그래프를 인접 리스트로 저장하기
s, e = map(int, input().split())
A[s].append(e) # 양방향 에지이므로 양쪽에 에지를 더하기
A[e].append(s)
for i in range(N):
DFS(i, 1)
if arrive:
break
if arrive:
print(1)
else:
print(0)