import sys
from collections import deque
def input():
return sys.stdin.readline().rstrip()
N,M = map(int,input().split())
graph = [[] for _ in range(N+1)]
for ind in range(M):
arr = list(map(int,input().split()))
lens = len(arr)
for arr_ind in range(lens-1):
cur_node = arr[arr_ind]
if arr_ind == 0:
graph[cur_node].append([-1,arr[arr_ind+1],ind])
else:
graph[cur_node].append([arr[arr_ind-1],arr[arr_ind+1],ind])
start_node, end_node = map(int,input().split())
INF = float('inf')
distance_list = [INF for _ in range(N+1)]
visited_node = [True for _ in range(N+1)]
distance_list[start_node] = 0
queue = deque()
queue.append((start_node,0,-1))
while queue:
node,cnt,prev_ind = queue.popleft()
for left_node,right_node,position in graph[node]:
if left_node != -1:
if prev_ind == -1:
distance_list[left_node] = cnt
queue.append((left_node,cnt,position))
else:
temp = 1 if prev_ind != position else 0
if distance_list[left_node] > cnt + temp:
distance_list[left_node] = cnt + temp
queue.append((left_node,cnt+temp,position))
if right_node != -1:
if prev_ind == -1:
distance_list[right_node] = cnt
queue.append((right_node,cnt,position))
else:
temp = 1 if prev_ind != position else 0
if distance_list[right_node] > cnt + temp:
distance_list[right_node] = cnt + temp
queue.append((right_node,cnt+temp,position))
if distance_list[end_node] == INF:
print(-1)
else:
print(distance_list[end_node])
처음 풀었던 풀이는 좋은 풀이는 아닌것처럼 보인다.
처음 풀었던 방식은 다음과 같다. 현재 노드에 좌우 노드와 현재 노선을 집어넣어준다.
그리고 bfs를 하면서 노선이 바뀔때 그 값이 현재 있는 값보다 적으면 바꿔서 queue에 넣어주는 방식대로 했다.
이 방식의 문제점은 한 노선이 엄청 길면 모든 노선들을 전부 하나하나씩 다 탐색을 하는 것이다.
import sys
from collections import deque
def input():
return sys.stdin.readline().rstrip()
N,M = map(int,input().split())
graph = []
subway_routelist = [[] for _ in range(N+1)]
for route_ind in range(M):
arr = set(map(int,input().split()))
arr.remove(-1)
for subway_num in arr:
subway_routelist[subway_num].append(route_ind)
graph.append(list(arr))
start_node, end_node = map(int,input().split())
visited = [-1 for _ in range(N+1)]
visited_subway = [-1 for _ in range(M)]
end_subway = []
for route_ind in range(M):
if end_node in graph[route_ind]:
end_subway.append(route_ind)
queue = deque()
route_cnt = 0
visited[end_node] = 0
for end_route in end_subway:
visited_subway[end_route] = route_cnt
for subway_num in graph[end_route]:
if visited[subway_num] == -1:
visited[subway_num] = route_cnt
queue.append(subway_num)
if visited[start_node] != -1:
print(0)
else:
while queue:
N = len(queue)
for _ in range(N):
node = queue.popleft()
for route in subway_routelist[node]:
if visited_subway[route] == -1:
visited_subway[route] = route_cnt + 1
for subway_num in graph[route]:
if visited[subway_num] == -1:
visited[subway_num] = route_cnt + 1
queue.append(subway_num)
route_cnt += 1
if visited[start_node] != -1:
break
print(visited[start_node])
이 풀이는 노선을 기준으로 bfs를 하는 방식이다.
먼저 사전 작업으로, subway_route_list에 현재 노선번호를 넣어준다.
graph에는 각 노선의 역정보를 넣어준다.
먼저 우리는 도착지점이 있는 route(노선)들을 전부 구한다. 그 노선이 있는 목록을 end_subway라고 하겠다.
그러면 우리는 이 route들의 모든 노선들은 환승이 없이 도착지점에 도착하는 것을 알 수 있다.
그러므로 우리는 visited_subway라는 노선의 방문을 체크하는 곳에 방문의 여부를 체크를 해준다.
그리고 난뒤에 우리는 이 노선(route)에 있는 역들도 전부 환승없이 방문 할 수 있는 것을 알 수 있다.
그러므로 역의 방문을 나타내는 visited에 방문을 체크해주고, 그때의 역번호를 queue에 넣어준다.
위와 같은 일련의 작업을 한뒤에는 우리가 구할 수 있는 것은 도착지점에서 한번의 환승도 없이 다닐 수 있는
모든 역들을 체크해준것이다.
그러면 우리는 현재 상태에서 start_node가 방문이 표시되었다 하면, 환승없이 start_node에서 end_node까지 갈수 있음을 알 수 있고,
그때는 0을 출력해준다.
만약 그렇지 않을때에는 bfs를 해주면 된다.
이 bfs는 하나의 queue 단위로 bfs를 돌려주면 되므로,
최초의 queue의 크기인 N만큼 popleft를 해주면서, 해당 역에서 갈 수 있는 노선을 갱신해주고,
이 노선에서 갈 수 있는 역 중에 가보지 않은 역들을 queue에 추가해주면된다.
이러한 방식을 통해 최소 환승 횟수를 알 수 있게 된다.
이 문제에서 주요한 점은 역을 중점으로 bfs를 돌리는 것이 아닌 노선을 중심으로 해서 bfs를 돌린다는 점을 주의해주면 된다.
'알고리즘 > 백준' 카테고리의 다른 글
[BOJ/백준] 3673 나눌 수 있는 부분 수열 (0) | 2021.09.02 |
---|---|
[BOJ/백준] 2023 신기한 소수 (0) | 2021.09.02 |
[BOJ/백준] 1766 문제집 (0) | 2021.09.02 |
[BOJ/백준] 1755 숫자놀이 (0) | 2021.09.02 |
[BOJ/백준] 1561 놀이공원 (0) | 2021.09.02 |