ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python 3] BOJ - 13308 "주유소"
    BOJ 2021. 12. 4. 20:52

     # 문제 링크

    https://www.acmicpc.net/problem/13308

     

    13308번: 주유소

    표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 도시의 수와 도로의 수를 나타내는 정수 N(2 ≤ N ≤ 2,500)과 정수 M(1 ≤ M ≤ 4,000)이 주어진다. 다음 줄에 각 도시 주유소의 리터당 가격이 도

    www.acmicpc.net

     

     # 풀이

     개인적으로 이 문제의 핵심은 다익스트라 알고리즘이라고 생각한다. 다만, 일반적인 다익스트라와는 다르게 상태 공간을 현재 정점의 번호가 idx, 현재 기름을 넣기 위해 드는 단위 비용을 cost일 때 드는 최소 비용인 2차원 상태 공간 d[idx][cost]라고 정의하자.

    <그림 1. 임의의 그래프 중 일부>

     위 그림 1은 임의의 그래프 중 일부 정점과 간선을 나타낸 그림이다. 우선 i번째 정점를 생각해보자. 이 때 i는 시작점일 수도 있다. 현재 i번째에서 주유를 하게 되면 거리 당 드는 비용은 5가 된다. 그런데, i에 도달하기 위해서 거친 0개 이상의 정점이 반드시 있었을 것이다. 예를 들어 i번째 정점을 가기 위해 거친 정점이 3개라고 가정해보자. 이 때 각각의 주유소의 단위 비용이 1,10,3이라고 하자. 또한 그 중에서 i번째 정점에 도착하기 직전에 단위 비용 3을 이용하여 i번째 정점에 왔다고 하자.

     그렇다면, 현재 i번째에서 j 혹은 k로 이동하기 전에 반드시 각각의 거리만큼 주유를 해야 한다. 그렇기 때문에 i번째 정점에서 내릴 수 있는 의사결정은 현재 i번째 정점을 오기 위해 지불했던 단위 비용을 계속 쓸 것인가, 혹은 이 때까지 썼던 단위 비용 대신 현재 i번째 정점의 단위 비용을 쓸 것인가이다. 

     이 때, 첫번째 의사결정을 통해 정점 j로 간다고 가정해보자. 이 때 드는 비용은 단위 비용 X 거리이므로, 3 X 17 = 51임을 알 수 있다. 두번째 의사결정의 경우는 5 X 17 = 85이다. 문제에서 거리와 단위 비용 모두 양수이기 때문에 단위 비용이 적은 쪽을 선택해야 총 비용이 작아지는 것은 자명하다. 따라서, 애초에 정점 i를 올 때 선택할 수 있는 단위 비용들, 즉 1,10,3중 단위 비용이 1인 경우를 선택해야 비용이 최소가 된다.

     따라서, 현재 정점에서 다른 정점으로 이동할 때는 현재 기름을 넣기 위해 드는 단위 비용인 cost에 가야하는 거리인 next_dist를 곱한 만큼의 비용이 들고, 이것이 d[next][cost]보다 작을때만 상태 공간을 변경해야 한다. 또한, 상태 공간을 변경할때는 다음 정점의 단위 비용과 현재 정점의 단위 비용 중 더 작은 값으로 바꿔줘야 정답을 구할 수 있다

     

     # 코드

    import sys, heapq
    
    # dijkstra : 현재 정점이 idx, 현재 단위 비용이 cost일 때 n번째 정점까지 가기 위해 드는 최소 비용을 리턴하는 함수
    def dijkstra():
        inf = 98765432109876543210
        # d : 상태 공간 배열
        d = [[inf] * (max(arr) + 1) for _ in range(n + 1)]
        q = []
        d[1][arr[1]] = 0
        heapq.heappush(q, (0, arr[1], 1))
        while q:
            # now_dist : 현재 드는 총 비용
            # now_cost : 현재 정점에서 다른 정점으로 갈 때 드는 단위 비용
            # now : 현재 정점
            now_dist, now_cost, now = heapq.heappop(q)
            # 도착 시 정답 리턴
            if now == n:
                return now_dist
            if d[now][now_cost] < now_dist:
                continue
            for (next, next_dist) in adj[now]:
                # next_cost : 다음 정점으로 도착해서 쓸 단위 비용
                next_cost = min(arr[next], now_cost)
                # 현재 총 비용이 다음 정점으로 가기 위해 드는 비용보다 작다면 우선순위 큐에 삽입
                if d[next][now_cost] > now_dist + now_cost * next_dist:
                    d[next][now_cost] = now_dist + now_cost * next_dist
                    heapq.heappush(q, (now_dist + now_cost * next_dist, next_cost, next))
    
    # 입력부
    n, m = map(int, sys.stdin.readline().split())
    arr = [-1] + list(map(int, sys.stdin.readline().split()))
    adj = [[] for _ in range(n + 1)]
    for _ in range(m):
        a,b,c = map(int, sys.stdin.readline().split())
        adj[a].append((b,c))
        adj[b].append((a,c))
        
    # 정답 출력
    print(dijkstra())

    'BOJ' 카테고리의 다른 글

    [Python 3] BOJ - 2305 "자리 배치"  (0) 2021.12.14
    [Python 3] BOJ - 13711 "LCS 4"  (0) 2021.12.08
    [Python 3] BOJ - 17182 "우주 탐사선"  (0) 2021.11.30
    [Python 3] BOJ - 3430 "용이 산다"  (0) 2021.11.29
    [Python 3] BOJ - 16565 "N포커"  (0) 2021.11.21

    댓글

Designed by Tistory.