https://www.acmicpc.net/problem/1753
문제 분석
- 방향 그래프가 주어졌을 때
- 주어진 시작 시점에서 다른 모든 정점으로의 최단 경로를 구하라
- v : 정점의 개수, e : 간선의 개수
- 모든 정점에 1~v까지의 번호가 있음
- s : 정점 시작번호
- e개의 각 간선을 나타내는 세개의 정수 (u, v, w)
- u에서 v로 가는 (방향이 있음)
- 가중치 w인 간선이 존재
- 서로 다른 두 정점 사이에 여러개의 간선이 존재할 수도 있다.
- K에서 각 정점으로 가는 최단거리 출력
- 자기 자신이면 0
- 경로가 없으면 'INF' 출력
코드 설계
1차
- BFS ?
- 시작 정점 K → 도착 위치이면 거리 return
- 처음이 작다고 최단거리가 될거라는 보장이 없으니 모든 경우의 수를 구해야 할 듯 (완탐?)
- 모든 도착 지점에 대한 도착 횟수를 리스트에 저장
- 마지막에 다 끝나면 min(list)
- 맨 처음 1~v 까지 돌면서 도착지점 확인
- 모든 리스트를 다 돌건데, 만약 이전에 갔던 간선이면 또 가지 x (모든 경우의 수를 확인할 것이기 때문에 다른 경우에 수에서 체크될 것)
- 어떻게 모든 경우의 수 체크?
- 현재 위치는 시작점
- 간선 리스트를 하나씩 돌면서 만약 현재 시작점인 값이 있으면
- 모든 리스트를 다 돌건데, 만약 이전에 갔던 간선이면 또 가지 x (모든 경우의 수를 확인할 것이기 때문에 다른 경우에 수에서 체크될 것)
2차
1. 도착한 것을 어떻게 확인할 것인가
- 현 위치와 도착하려는 위치가 같으면 도착
2. 어떻게 최단 거리를 찾을 것인가
- 현재 위치에서 시작하고 end_point 에서 끝나는 값이 있는지 확인
- 그런 값이 여러개라면 w가 가장 작은거
- 없으면
- 이동할 수 있는 모든 거리 추적
- 시작과 도착이 같으면 w 작은거 선정
3. 어떻게 경로가 존재하지 않음을 확인하는가
- 더 이상 나아갈 수 없을 때 (나의 현재 위치에서 시작할 수 있는 리스트 값이 없을 때)
정답 코드
1차.. 실패.. 엉망진창
import sys
input = sys.stdin.readline
from collections import deque
V, E = map(int, input().split())
start = int(input())
move = deque()
for i in range(E) :
move.append(list(map(int, input().split())))
distance = []
for end in range(1, V+1) : # 도착지점 1~v
print('end : ', end)
dis = 0
if end == start:
print(0)
continue
current = start
while move : # 모든 간선 확인
u,v,w = move.popleft()
if end in (u,v) :
if current in (u, v): # start와 다른 값을 현재 위치로 이동하고
if u == current:
current = v
else:
current = u
dis += w
distance.append(dis) # todo 이러면 아직 한 경우의 수만 탐색하는 건데..
else :
move.append((u,v,w))
continue
print(min(distance))
실패..
다익스트라 알고리즘
다른 사람 풀이 1
출처 : https://jie0025.tistory.com/199
다익스트라의 기본
- 다익스트라는 heapq를 이용하면 빠르다.
- 최단 거리 테이블
- 연결 정보
코드 설계
- u 에서 v로 가는 일방향그래프이기 때문에 graph = [[] for _ in range(V+1) ] 노드의 개수만큼 2차원 리스트를 만든 다음, graph[u].append() 를 해주고, 노드번호와 가중치를 함께 묶어서 입력
- 최단 거리 테이블 생성 (노드의 개수 V+1 만큼 → V+1은 노드 번호가 1부터 시작되기 때문)
- 최단거리를 확인하기 위해 INF = int(1e9)라는 변수를 생성, 최단거리일 경우 업데이트
다익스트라 (시작 노드 번호)
- import heapq
- hapq를 사용하기 위해 q = [ ] 리스트 생성
- heapq.heappush( q, value )
value 부분에 시작노드이므로 거리는 (0, 시작노드번호)를 함께 묶어서 힙큐에 넣어준다. - 최단거리테이블[시작노드] = 0 으로 초기화
- q가 빌때까지 반복
- heapq.heappop(q) : 큐에서 거리(dist), 노드번호(now)를 꺼낸다.
- 만약에 꺼낸 거리값이 최단거리테이블( distance[꺼낸 노드번호] ) 에 기록된 정보보다 값이 크면, 최단거리 정보가 아니기 때문에 continue 로 무시한다.
- 그게 아니라면 최단거리 정보이므로 다음과 같은 작업을 수행한다.
- for i in graph[꺼낸노드번호]:
- 꺼낸노드번호에서 갈수 있는 노드와 거리정보를 i를 통해 한개씩 접근
→ i[0] : 현재 노드에서 갈 수 있는 노드 번호
→ i[1] : 현재 노드에서 갈 수 있는 노드 번호까지의 거리
i[0]까지의 최소비용(cost)은 >>> 현재 노드의 최소비용(dist) + i[1] 이다. 만약에 cost값이 최단 거리 테이블의 거리 정보보다 작으면, 업데이트 해주고 힙큐에 정보를 넣어준다.
이 과정을 반복하면 방문할 수 있는 노드에 대하여 최단거리테이블이 모두 갱신된다.
다익스트라 함수가 끝나면 최단 거리 테이블이 모두 갱신되어있으므로 각 i번쨰 노드까지의 거리는 최단거리테이블의 정보를 출력해주면된다.
만약 방문하지 못한 노드는 INF(1e9)가 그대로 남아 있을테니 확인후 "INF"를 출력한다.
for i in range(1,V+1):
if distance[i] == INF:
print("INF")
else: print(distance[i])
import sys
import heapq
input = sys.stdin.readline
INF = int(1e9)
def dijkstra(start):
q= []
heapq.heappush(q,(0,start))
distance[start] = 0
while q:
dist, now = heapq.heappop(q)
if distance[now] < dist:
continue
#현재 노드와 연결된 인접 노드 확인
for i in graph[now]:
cost =dist+ i[1]
if cost < distance[i[0]] :
distance[i[0]] = cost
heapq.heappush(q,(cost,i[0]))
#V == 5일 때 1~5까지 노드가 있는거임.
V, E = map(int,input().split())
snode = int(input()) #시작 노드
graph = [[] for _ in range(V+1)]
distance = [INF] * (V+1) #최단 거리 테이블
#연결 정보 입력
for _ in range(E):
u,v,w = map(int,input().split())
graph[u].append((v,w))
dijkstra(snode)
#i번째 줄에 i번 정점으로의 최단 경로의 경로값을 출력
for i in range(1,V+1):
if distance[i] == INF:
print("INF")
else:
print(distance[i])
2회차 - 25.03.31
실패..
import sys
input = sys.stdin.readline
from collections import deque
v, e = map(int, input().split())
# v - 정점의 번호 : 1~v
start_v = int(input())
# 시작점에서 각 정점까지의 최단거리
edge = [[0,0] for _ in range(v)]
visited = [False for _ in range(v)]
for _ in range(e) :
a,b,w = map(int, input().split())
edge[a][b] = edge[b][a] = w
d = deque()
d.append((start_v, 0))
visited[start_v] = True
while d :
cur_v, dis = d.popleft()
# 경로가 존재하지 않는다면 ('inf')
# 각 정점에 대한 최단거리? -> 어떻게?
# 있는 간선 중 가장 작은 가중치를 가지는 값 (그리디)
# 시작 점에 대해 다음 모든 정점을 갈 수 있는 모든 경우 확인?
# 해당 경우에 대해 최단 거리 찾기
for i in range(v) :
if edge[i][cur_v] :
d.append((i, dis+edge[i][cur_v]))
visited[i] = True
해설
- 가중치가 있기 때문에 u -> v로 가는 일방향 그래프
- 정점은 1부터 v : (v+1)
import sys, heapq
input = sys.stdin.readline
INF = int(1e9)
def dijkstra(start) :
hq = []
# 시작노드로 가기 위한 최단 경로는 0
heapq.heappush(hq, (0, start))
distance[start] = 0
while hq :
# 가장 최단 거리가 짧은 노드에 대한 정보 꺼내기
dist, now = heapq.heappop(hq)
# 꺼낸 값이 최단거리 테이블 (distance)에 기록된 정보보다 값이 크다면, 최단거리 정보가 아니기때뭉네 무시
if distance[now] < dist :
continue
# 현재 노드와 인접한 노드들 확인
# i[0] : 현재 노드에서 갈 수 있는 노드 번호
# i[1] : 가중치
for i in graph[now] :
cost = dist + i[1]
if cost < distance[i[0]] :
distance[i[0]] = cost
heapq.heappush(hq, (cost, i[0]))
V, E = map(int, input().split())
start_node = int(input())
graph = [[] for _ in range(V+1)]
# 최단 거리 테이블을 무한으로 초기화
distance = [INF] * (V+1)
# 간선 정보 입력
for _ in range(E) :
u, v, w = map(int, input().split())
graph[u].append((v, w))
dijkstra(start_node)
for i in range(1, V+1) :
if distance[i] == INF :
print("INF")
else :
print(distance[i])
3회차 - 25.04.03
1차 - 예시 통과, 틀림
import sys, heapq
input = sys.stdin.readline
V, E = map(int, input().split())
s_node = int(input())
INF = 100000 # 모든 간선의 가중치는 10이하의 자연수이다.
# 시작노드에서 각 노드에 대해 최소 거리를 저장할 리스트
distance = [INF for _ in range(V+1)] # 최단 거리를 구하는 거니까 다 큰 값으로 설정
# 노드는 1번부터 V까지 방문 여부 확인
visited = [False for _ in range(V+1)]
g = [[] for _ in range(V+1)] # idx 노드에 대해 [연결노드, 가중치]
for _ in range(E) :
u, v, w = map(int, input().split())
# g[u] = [v,w] # 하나만 연결된게 아닐수도 있으니 append
g[u].append([v,w])
hq = []
heapq.heappush(hq, (s_node, 0))
visited[s_node] = True
distance[s_node] = 0 # 시작노드에서 시작 노드까지의 (최소)거리는 0
while hq :
# 현재 노드, 거리
now_node, dis = heapq.heappop(hq) # 최단거리를 알아서 먼저 pop
# 현재 노드에 대해 연결된 노드들의 최단 거리 업데이트
# g[now_node] 개수 -> 길이만큼 검사 : 연결된 노드에 대해서 최단거리 업데이트
# 현재 노드와 연결된 노드들의 거리가 이전 보다 짧으면 update
# 그 중 아직 방문하지 않은 노드는 heap_push
for i in range(len(g[now_node])) :
# 현재 노드에 가중치를 더한것 : 현재 노드에서 연결된 노드로 넘어가는 비용이 더 적으면 update
# 연결된 노드의 값을 update 할지 말지 결정해야 하기 때문에
# dis[next_node]
next_node = g[now_node][i][0]
if g[now_node][i][1]+dis < distance[next_node] :
distance[next_node] = g[now_node][i][1] + dis
if not visited[next_node] :
heapq.heappush(hq, (g[now_node][i][0], distance[next_node]))
visited[next_node] = True
for i in range(1, V+1) :
if distance[i] == INF :
print('INF')
continue
print(distance[i])
'''
다익스트라 알고리즘
1. 시작 노드에서 각 노드들까지의 거리 확인
2. 그 중 최소 노드 확인
3. 최소 노드 방문
4. 해당 노드에서 다른 노드로 이동할 때 최소 거리 갱신
5. 노드 이동시 방문 처리
출력 : g[1] ~ g[V] 시작노드에서부터의 최단 거리
'''
틀린 이유
1. 힙에 넣을 때 현재는 (node, distance) 순서로 넣고 있는데, (dis, node) 순서로 넣어야 힙에서 pop 할 때, 최소 비용을 기준으로 나온다.
2. 가중치가 있기 때문에 g에 대해서 입력할 때 단방향 입력을 하였다. 따라서 visited를 검사할 필요 x
+ 다익스트라 알고리즘에서는 힙에서 꺼낼 때 방문 처리 해야 한다.
2차
import sys, heapq
input = sys.stdin.readline
V, E = map(int, input().split())
s_node = int(input())
INF = int(1e9) # 모든 간선의 가중치는 10이하의 자연수이다.
# 시작노드에서 각 노드에 대해 최소 거리를 저장할 리스트
distance = [INF for _ in range(V+1)] # 최단 거리를 구하는 거니까 다 큰 값으로 설정
# 노드는 1번부터 V까지 방문 여부 확인
# visited = [False for _ in range(V+1)]
g = [[] for _ in range(V+1)] # idx 노드에 대해 [연결노드, 가중치]
for _ in range(E) :
u, v, w = map(int, input().split())
# g[u] = [v,w] # 하나만 연결된게 아닐수도 있으니 append
g[u].append([v,w])
hq = []
# heapq.heappush(hq, (s_node, 0)) # (거리, 노드) 순으로 넣어야 최소 거리 순으로 pop 된다!!
heapq.heappush(hq, (0, s_node)) # (거리, 노드) 순으로 넣어야 최소 거리 순으로 pop 된다!!
# visited[s_node] = True
distance[s_node] = 0 # 시작노드에서 시작 노드까지의 (최소)거리는 0
while hq :
# 현재 노드, 거리
dis, now_node = heapq.heappop(hq) # 최단거리를 알아서 먼저 pop
# 현재 노드에 대해 연결된 노드들의 최단 거리 업데이트
# g[now_node] 개수 -> 길이만큼 검사 : 연결된 노드에 대해서 최단거리 업데이트
# 현재 노드와 연결된 노드들의 거리가 이전 보다 짧으면 update
# 그 중 아직 방문하지 않은 노드는 heap_push
for i in range(len(g[now_node])) :
# 현재 노드에 가중치를 더한것 : 현재 노드에서 연결된 노드로 넘어가는 비용이 더 적으면 update
# 연결된 노드의 값을 update 할지 말지 결정해야 하기 때문에
# dis[next_node]
next_node = g[now_node][i][0]
if g[now_node][i][1]+dis < distance[next_node] :
distance[next_node] = g[now_node][i][1] + dis
# if not visited[next_node] :
# heapq.heappush(hq, (g[now_node][i][0], distance[next_node]))
heapq.heappush(hq, (distance[next_node], g[now_node][i][0]))
# visited[next_node] = True
for i in range(1, V+1) :
if distance[i] == INF :
print('INF')
continue
print(distance[i])
'''
다익스트라 알고리즘
1. 시작 노드에서 각 노드들까지의 거리 확인
2. 그 중 최소 노드 확인
3. 최소 노드 방문
4. 해당 노드에서 다른 노드로 이동할 때 최소 거리 갱신
5. 노드 이동시 방문 처리
'''
주석 정리
import sys, heapq
input = sys.stdin.readline
V, E = map(int, input().split())
s_node = int(input())
INF = int(1e9)
distance = [INF for _ in range(V+1)]
g = [[] for _ in range(V+1)]
for _ in range(E) :
u, v, w = map(int, input().split())
g[u].append([v,w])
hq = []
heapq.heappush(hq, (0, s_node))
distance[s_node] = 0
while hq :
dis, now_node = heapq.heappop(hq)
for i in range(len(g[now_node])) :
next_node = g[now_node][i][0]
if g[now_node][i][1]+dis < distance[next_node] :
distance[next_node] = g[now_node][i][1] + dis
heapq.heappush(hq, (distance[next_node], g[now_node][i][0]))
for i in range(1, V+1) :
if distance[i] == INF :
print('INF')
continue
print(distance[i])
'코딩 테스트 > 백준' 카테고리의 다른 글
[Python] 백준 10810 공 넣기 (0) | 2025.01.06 |
---|---|
[Python] 백준 10951 A+B - 4 (1) | 2025.01.03 |
[Python] 백준 24060 알고리즘 수업 - 병합 정렬 1 (0) | 2024.12.31 |
[Python] 백준 1157 단어 공부 (0) | 2024.12.31 |
[Python] 백준 19532 수학은 비대면강의입니다 (0) | 2024.12.31 |