알고리즘문제풀이

백준 13907 세금 (python)

배우겠습니다 2023. 3. 23. 16:02

문제 링크

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

 

13907번: 세금

첫 번째 줄에 세 정수 N (2 ≤ N ≤ 1,000), M (1 ≤ M ≤ 30,000), K (0 ≤ K ≤ 30,000)가 주어진다. 각각 도시의 수, 도로의 수, 세금 인상 횟수를 의미한다. 두 번째 줄에는 두 정수 S와 D (1 ≤ S, D ≤ N, S ≠ D

www.acmicpc.net

 

아이디어

N이 1000이다. 따라서 floyd가 아닌 다익스트라를 쓰는건 확실하다.

세금이 인상될때 마다 다익스트라를 쓴다면?

pq를 쓰는 다익스트라를 쓴다고 해도 O(K * (M + N)logN)은 썩 좋아 보이지 않는다.

다른 풀이가 필요하다.

우선 세금이 없는 경우 S->D의 특정 경로의 통행료를 A라하자. 이때 거친 간선의 수를 B라하면

세금이 x원 부과된 경우 통행료는 A + B * x이다.

이식을 최소로 하기 위해선

1. 통행료가 같다면 거친 간선의 수가 최소인 것이 최적이다.

2. 거친 간선의 수가 같다면 통행료가 최소인 것이 최적이다.

라는 생각을 할 수 있다.

(이 생각으로 풀이는 여러개 나올거 같긴 하다.)

 

풀이

우선 세금이 없을때도 구해야하므로 그건 그냥 구해도 된다.

나는 한번에 다~ 구할 것이다.

path라는 것을 선언한다. path[node][lv]는 간선을 lv만큼 거쳤을때 S->node의 최소 통행비이다.

(난 완전 그래프가 아닌 이상 노드까지 도달하기에 거치는 간선수는 한정적일 것이라 보고 hash table(dictionary)로 선언했으나 2차원 배열(리스트)도 상관없을 것이다.)

S -> node의 최소 통행비가 X이고 간선을 L만큼 거쳤다고 하자.

우리는 S -> node 경로의 통행비가 X보다 큰 주제에 거친 간선도 L이상이면 그건  굳이 필요없음을 유념해야 한다.

bfs에 기반한 다익스트라(최적화 안한 다익스트라)를 쓴다면

1. 간선을 적게 쓸때 통행료

2. 최소 통행료

둘다 구해줄 수 있다.

그렇게 다익스트라를 돌리고

path[D]에는 우리가 필요한 간선을 lv개 썻을때 최소통행료 정보가 들어있다.

그걸로 세금을 처리하면 된다. A + B * x

 

코드

더보기

import sys
from collections import deque

 

input = sys.stdin.readline
N, M, K = map(int, input().split())
S, D = map(int, input().split())
g = {n: [] for n in range(1, N + 1)}
for _ in range(M):
    a, b, w = map(int, input().split())
    g[a].append((b, w))
    g[b].append((a, w))
for n in range(1, N + 1):
    g[n].sort(reverse=True)
q = deque([(0, S, 0)])
distance = [float('inf')] * (N + 1)
distance[S] = 0
path = {i: {} for i in range(1, N + 1)}
path[S][0] = 0
while q:
    dist, node, level = q.popleft()
    for n, d in g[node]:
        tmp = dist + d
        lv = level + 1
        if lv in path[n]:
            if path[n][lv] > tmp:
                path[n][lv] = tmp
        else:
            if tmp < distance[n]:
                path[n][lv] = tmp
        if distance[n] > tmp:
            distance[n] = tmp
            q.append((tmp, n, lv))
print(distance[D])
for _ in range(K):
    current = float('inf')
    k = int(input())
    for l in path[D]:
        path[D][l] += l * k
        current = min(current, path[D][l])
    print(current)