https://school.programmers.co.kr/learn/courses/30/lessons/12978
문제 설명
N개의 마을로 이루어진 나라가 있습니다. 이 나라의 각 마을에는 1부터 N까지의 번호가 각각 하나씩 부여되어 있습니다. 각 마을은 양방향으로 통행할 수 있는 도로로 연결되어 있는데, 서로 다른 마을 간에 이동할 때는 이 도로를 지나야 합니다. 도로를 지날 때 걸리는 시간은 도로별로 다릅니다. 현재 1번 마을에 있는 음식점에서 각 마을로 음식 배달을 하려고 합니다. 각 마을로부터 음식 주문을 받으려고 하는데, N개의 마을 중에서 K 시간 이하로 배달이 가능한 마을에서만 주문을 받으려고 합니다. 다음은 N = 5, K = 3인 경우의 예시입니다.
위 그림에서 1번 마을에 있는 음식점은 [1, 2, 4, 5] 번 마을까지는 3 이하의 시간에 배달할 수 있습니다. 그러나 3번 마을까지는 3시간 이내로 배달할 수 있는 경로가 없으므로 3번 마을에서는 주문을 받지 않습니다. 따라서 1번 마을에 있는 음식점이 배달 주문을 받을 수 있는 마을은 4개가 됩니다.
마을의 개수 N, 각 마을을 연결하는 도로의 정보 road, 음식 배달이 가능한 시간 K가 매개변수로 주어질 때, 음식 주문을 받을 수 있는 마을의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
마을의 개수 N은 1 이상 50 이하의 자연수입니다.
road의 길이(도로 정보의 개수)는 1 이상 2,000 이하입니다.
road의 각 원소는 마을을 연결하고 있는 각 도로의 정보를 나타냅니다.
road는 길이가 3인 배열이며, 순서대로 (a, b, c)를 나타냅니다.
a, b(1 ≤ a, b ≤ N, a != b)는 도로가 연결하는 두 마을의 번호이며, c(1 ≤ c ≤ 10,000, c는 자연수)는 도로를 지나는데 걸리는 시간입니다.
두 마을 a, b를 연결하는 도로는 여러 개가 있을 수 있습니다.
한 도로의 정보가 여러 번 중복해서 주어지지 않습니다.
K는 음식 배달이 가능한 시간을 나타내며, 1 이상 500,000 이하입니다.
임의의 두 마을간에 항상 이동 가능한 경로가 존재합니다.
1번 마을에 있는 음식점이 K 이하의 시간에 배달이 가능한 마을의 개수를 return 하면 됩니다.
가중치가 있는 그래프에서 최단거리를 탐색하기 위해 다익스트라알고리즘을 구현해야하는 문제, bfs로 풀었다가 여러번 틀렸다.
def solution(N, road, K):
answer = 0
road_dict = {i: {} for i in range(1, N + 1)}
return answer
먼저 리스트의 형태로 주어진 그래프를 딕셔너리 형태로 만들어준다.
그래프의 각 노드를 key값으로 하고 이후에 인접한 노드와 그 거리를 각각 value의 key, value로 만들기 위해서 value의 기본 값을 딕셔너리로 작성을 한다.
# def solution(N, road, K):
# answer = 0
# road_dict = {i: {} for i in range(1, N + 1)}
for r in road:
villiage, connected_villiage, _ = r
road_dict[villiage][connected_villiage] = 0
road_dict[connected_villiage][villiage] = 0
# return answer
이제 리스트 형태의 그래프인 road의 간선들을 road_dict에 표시해준다. 거리는 최소값을 반환하여 입력해야하기 때문에 우선 0으로 입력을 하고 각 노드의 간선만 입력을 해준다. road_dict의 key는 1 ~ N까지의 노드이고 각 Key의 value의 key는 해당 노드와 연결된 다른 노드를 나타낸다. 거리(가중치)를 나타내는 value의 value는 아직은 모두 0인 상태이다.
# def solution(N, road, K):
# answer = 0
# road_dict = {i: {} for i in range(1, N + 1)}
# for r in road:
# villiage, connected_villiage, _ = r
# road_dict[villiage][connected_villiage] = 0
# road_dict[connected_villiage][villiage] = 0
for r in road:
villiage, connected_villiage, distance = r
if road_dict[villiage][connected_villiage] == 0:
road_dict[villiage][connected_villiage] = distance
else:
road_dict[villiage][connected_villiage] = min(distance, road_dict[villiage][connected_villiage])
if road_dict[connected_villiage][villiage] == 0:
road_dict[connected_villiage][villiage] = distance
else:
road_dict[connected_villiage][villiage] = min(distance, road_dict[connected_villiage][villiage])
# return answer
이제 각노드 사이의 가중치를 반영한다. 가중치가 0인 경우 현재 가중치를 즉시 입력하고 0이 아닌경우 이미 입력된 가중치와 비교하여 더 작은 가중치를 반영하여 동일한 경로에서 더 시간이 오래 걸리는 비효율적인 간선을 모두 제거해준다.
# def solution(N, road, K):
# answer = 0
# road_dict = {i: {} for i in range(1, N + 1)}
# for r in road:
# villiage, connected_villiage, _ = r
# road_dict[villiage][connected_villiage] = 0
# road_dict[connected_villiage][villiage] = 0
# for r in road:
# villiage, connected_villiage, distance = r
# if road_dict[villiage][connected_villiage] == 0:
# road_dict[villiage][connected_villiage] = distance
# else:
# road_dict[villiage][connected_villiage] = min(distance, road_dict[villiage][connected_villiage])
# if road_dict[connected_villiage][villiage] == 0:
# road_dict[connected_villiage][villiage] = distance
# else:
# road_dict[connected_villiage][villiage] = min(distance, road_dict[connected_villiage][villiage])
distance = dijkstra(road_dict)
for d in distance.values():
if d <= K:
answer += 1
# return answer
다익스트라 알고리즘을 함수로 작성해서(dijkstra()) 1번노드에서 출발하여 각 노드별로 거리가 얼마나 걸리는 지 반환하여 distance라는 변수에 저장한다.
이제 distance의 모든 value를 검사해서 거리가 K이하인 마을의 수를 반환하면 된다.
def dijkstra(graph, start=1):
distances = {node: float('inf') for node in graph}
distances[start] = 0
return distances
가중치 고려해서 최소거리를 탐색하기 위해 다익스트라 알고리즘을 함수로 작성한다. 탐색할 마을의 지도를 graph라고 하고 이 문제에서 시작마을은 항상 1이므로 start의 기본값을 1로 설정한다.
각 노드별로 최단 거리를 반환할 예정이므로 각 노드별 거리는 임시로 무한대로 설정한다. 또한, 시작노드는 거리가 존재하지 않기 때문에 0으로 설정하고 탐색을 시작한다.
# def dijkstra(graph, start=1):
# distances = {node: float('inf') for node in graph}
# distances[start] = 0
explore = [(0, start)]
while explore:
current_distance, current_location = explore.pop(0)
if current_distance > distances[current_location]:
continue
# return distances
출발노드부터 현재 노드까지의 거리(0),과 현재 노드(start)를 explore에 입력하고 탐색을 시작한다.
explore의 원소가 존재하지 않을 때 까지 반복을 하고 이것은 탐색할 노드가 더이상 없다는 것을 의미한다.
그리고 조건문을 통해서 현재 탐색중인 노드까지의 거리가 distances에 입력되어있는 현재 노드 까지의 거리보다 클 경우, 해당 노드는 이미 탐색한 노드이거나 최적화된 거리가 아니라는 의미이므로 탐색하지 않고 다음 노드를 탐색한다.
# def dijkstra(graph, start=1):
# distances = {node: float('inf') for node in graph}
# distances[start] = 0
# explore = [(0, start)]
# while explore:
# current_distance, current_location = explore.pop(0)
# if current_distance > distances[current_location]:
# continue
for adjacent_node, adjacent_distances in graph[current_location].items():
expected_distance = adjacent_distances + current_distance
if expected_distance < distances[adjacent_node]:
distances[adjacent_node] = expected_distance
explore.append((expected_distance, adjacent_node))
# return distances
현재 탐색중인 그래프의 현재위치의 모든 key, value에 대해서 반복문을 작성한다. (각각, 현재 노드와 연결된 노드의 번호, 가중치)
현재까지의 거리와 다음 노드까지의 거리를 더해서 expected_distance라는 변수에 저장한다. 이 값이 distances에 이미 입력되어 있는 인접노드까지의 최단거리 보다 긴 경우 해당 expected_distance는 최단거리가 아니라는 의미이므로 다음 노드를 탐색한다.
그러나 인접노드까지의 최단거리보다 짧은 경우, 해당 노드 까지의 거리를 새롭게 업데이트 한 뒤 탐색할 노드에 추가해준다.
def dijkstra(graph, start=1):
distances = {node: float('inf') for node in graph}
distances[start] = 0
explore = [(0, start)]
while explore:
current_distance, current_location = explore.pop(0)
if current_distance > distances[current_location]:
continue
for adjacent_node, adjacent_distances in graph[current_location].items():
expected_distance = adjacent_distances + current_distance
if expected_distance < distances[adjacent_node]:
distances[adjacent_node] = expected_distance
explore.append((expected_distance, adjacent_node))
return distances
따라서 위의 함수를 통해 graph의 1번 노드에서 출발해서 각 노드까지 도착하기 위한 최단거리를 반환할 수 있다.
def solution(N, road, K):
answer = 0
road_dict = {i: {} for i in range(1, N + 1)}
for r in road:
villiage, connected_villiage, _ = r
road_dict[villiage][connected_villiage] = 0
road_dict[connected_villiage][villiage] = 0
for r in road:
villiage, connected_villiage, distance = r
if road_dict[villiage][connected_villiage] == 0:
road_dict[villiage][connected_villiage] = distance
else:
road_dict[villiage][connected_villiage] = min(distance, road_dict[villiage][connected_villiage])
if road_dict[connected_villiage][villiage] == 0:
road_dict[connected_villiage][villiage] = distance
else:
road_dict[connected_villiage][villiage] = min(distance, road_dict[connected_villiage][villiage])
distance = dijkstra(road_dict)
for d in distance.values():
if d <= K:
answer += 1
return answer
'코딩일기' 카테고리의 다른 글
알고리즘 코드카타 124- 미로 탈출 (0) | 2024.08.10 |
---|---|
알고리즘 코드카타 123- 하노이의 탑 (0) | 2024.08.09 |
알고리즘 코드카타 122 - 테이블 해시 함수 (0) | 2024.08.08 |
알고리즘 코드카타 121 - 시소짝꿍 (0) | 2024.08.06 |
SQL 코드카타 181 - Draw The Triangle 1 (0) | 2024.08.06 |