0-1 BFS는 가중치가 0과 1로만 이루어진 그래프 상에서 최단거리를 찾는 알고리즘입니다.
BFS는 가중치가 없는 그래프에서 최단거리를 찾을 수 있는 알고리즘입니다.
가중치가 있는 그래프에서의 최단거리는 다익스트라 알고리즘을 통해서 구할 수 있습니다.
정리하면 다익스트라는 그리디 하지만 BFS는 그리디하지 않기에, 가중치가 있는 그래프의 경우 BFS를 쓸 수 없다고 설명할 수 있습니다.
그러나 가중치가 0 또는 1만 존재할 경우는 특수한 경우로써 BFS로 최단경로를 구할 수 있습니다.
일반 큐 대신 양방향 큐를 사용하여 가중치가 0인 노드는 앞부분에 삽입, 1인 노드는 뒷부분에 삽입함으로써 가장 가까운 노드부터 BFS탐색을 할 수 있기 때문입니다.
이유는 딱 하나 '빠르다'
다익스트라를 쓰던, 0-1 BFS를 쓰던 문제는 똑같이 풀립니다. 그러나 특수조건에서만 사용할 수 있는 0-1 BFS를 굳이 쓰는 이유는 딱 하나, '빠르기 때문'입니다.
아래의 조건에서 시간복잡도를 계산해보겠습니다.
알고리즘은 아래와 같은 과정을 반복합니다.
시간복잡도는 최악의 상황을 기준으로 계산하기 때문에 둘의 과정을 고려했을 때 O(ElogE)가 됩니다.
항상 간선의 숫자는 노드의 갯수 제곱보다 작기 때문에 가 성립하고 이므로 시간복잡도 계산방식에 의해 상수 2를 버리고 O(logE) = O(logV)로 나타낼 수 있습니다.
최종 시간복잡도 : O(ElogV)
BFS 탐색은 최단거리를 찾기 전까지 모든 노드를 한 번씩 방문하기 때문에 기본적으로 선형탐색입니다.
아래와 같은 과정을 반복합니다.
visited = [False] * V
deque.appendleft(0, root)
while deque:
cost, current_node = deque.popleft()
visited[current_node] = True
for node in graph[current_node]:
if not visited[node]:
if cost of current_node to node == 0:
deque.appendleft((cost, node))
elif cost of current_node to node == 1:
deque.append((cost + 1, node))
의사코드와 알고리즘에서의 시간복잡도를 종합해보면, 각 노드에 대하여 2, 3, 4번 과정을 반복하므로
위에서 O(V*E)가 O(E)로 치환되는 이유는 "(V * E) 는 전체 간선의 개수와 같아서" 라는데.....
🤔음...... 이 말의 뜻을 잘 모르겠다.
아시는 분이 계시다면 댓글로 설명해주시면 감사할것 같습니다. 🤔
그러나 0-1 BFS의 시간복잡도 또한 선형탐색을 따르므로 일반적인 DFS, BFS와 동일한 O(V+E) 라는것.
다익스트라 알고리즘보다 훨씬 훨씬 빠른 속도이기 때문에 문제에서 가중치 0, 1만 보인다면 바로 0-1 BFS로 참교육을 해주자.
👉 숨바꼭질 3
문제가 굉장히 심플하게 기술되어있지만, 평면좌표가 아닌 1차원 좌표기 때문에 그래프 알고리즘을 떠올리기가 쉽지 않을 수도 있습니다.
가장 빠른 수단을 찾는다는 점에서 다익스트라를 채용할 수 있지만, 가중치가 0, 1로만 이루어져 있다는 것을 캐치한다면 0-1 BFS로 굉장히 빠르게 혼내줄 수 있습니다.
두 방법 모두 파이썬 코드로 구현하면 아래와 같습니다.
"""
Dijkstra 풀이
"""
import heapq
import sys
N, K = map(int, sys.stdin.readline().split())
visited = [False] * 100001
heap = []
heapq.heappush(heap, (0, N))
while heap:
time, now = heapq.heappop(heap)
if now > 100000:
continue
visited[now] = True
if now == K:
print(time)
break
temp = now << 1
if temp <= 100000 and not visited[now << 1]:
heapq.heappush(heap, (time, now << 1))
if now + 1 <= 100000 and not visited[now + 1]:
heapq.heappush(heap, (time + 1, now + 1))
if now - 1 >= 0 and not visited[now - 1]:
heapq.heappush(heap, (time + 1, now - 1))
"""
0-1 BFS 풀이
"""
import sys
from collections import deque
N, K = map(int, sys.stdin.readline().split())
visited = [False] * 100001
d = deque()
d.appendleft((0, N))
while d:
time, now = d.popleft()
visited[now] = True
if now == K:
print(time)
break
if (now << 1) <= 100000 and not visited[now << 1]:
d.appendleft((time, now << 1))
if now + 1 <= 100000 and not visited[now + 1]:
d.append((time + 1, now + 1))
if now - 1 >= 0 and not visited[now - 1]:
d.append((time + 1, now - 1))