문제
그림 1은 어떤 도시의 주요 지점과 그 지점들 간의 이동시간을 나타낸 그래프이다. 그래프의 노드는 주요 지점을 나타내고 두 지점을 연결한 도로(에지)에 표시된 수는 그 도로로 이동할 때 걸리는 분 단위의 시간을 나타낸다. 두 지점 a와 b를 연결하는 도로는 도로(a,b)로 표시한다.
예를 들어 도로(1,2)와 도로(2,3)를 통하여 지점1에서 지점3으로 갈 때 걸리는 시간은 3분이다.
도로는 모두 양방향이라고가정하므로 도로(a,b)와 도로(b,a)를 지날 때 걸리는 시간은 항상 같다고 한다.
어떤 범죄용의자가 입력 데이터에 표시된 도시로 진입하여 이 도시를 가장 빠른 시간 내에 빠져나가고자 한다.
그런데 이 사실을 알고 있는 경찰이 어떤 하나의 도로(에지)를 선택하여 이 도로에서 검문을 하려고 한다.
따라서 용의자는 이 도로를 피해서 가장 빠르게 도시를 탈출하고자 한다.
이 경우 경찰이 검문을 위하여 선택하는 도로에 따라서 용의자의 가장 빠른 탈출시간은 검문이 없을 때에 비하여 더 늘어날 수 있다.
문제는 도로검문을 통하여 얻을 수 있는 탈출의 최대 지연시간을 계산하는 것이다. 추가설명은 다음과 같다.
- 두 개의 지점을 직접 연결하는 도로가 있는 경우, 그 도로는 유일하다.
- 도시의 지점(노드)은 1에서 N번까지 N개의 연속된 정수로 표시된다.
- 용의자가 도시에 진입하는 지점은 항상 1번이고 도시를 빠져 나가기 위하여 최종적으로 도달해야하는 지점은 항상 N번 지점이다.
- 용의자는 검문을 피해서 가장 빨리 도시를 빠져나가고자 하고, 경찰은 적절한 도로를 선택하여 이 용이자들의 탈출시간을 최대한 지연시키고자 한다.
- 각 도시 지점 간을 이동하는 시간은 항상 양의 정수이다.
입력 도시의 도로망에 따라서 경찰이 어떤 도로를 막으면 용의자는 도시를 탈출하지 못할 수도 있다. 이 경우 검문으로 인하여 지연시킬 수 있는 탈출시간은 무한대이다. 이 경우에는 -1을 출력해야 한다.
그림 1에서 볼 때 검문이 없을 경우 용의자가 도시를 탈출하는데 걸리는 시간은 4분이다.
만일 경찰이 도로(4,3)을 막으면 그 탈출시간을 지연시킬 수 없으므로 지연시간은 0이다.
만일 도로(2,3)을 막으면, 용의자들이 가장 빠르게 탈출할 수 있는 시간은 5분이므로 탈출지연시간은 1분이고, 도로(3,6)을 막으면 탈출지연시간은 2분이다.
여러분은 입력 데이터에 표시된 도로망을 읽고, 경찰이 한 도로를 막고 검문함으로써 지연시킬 수 있는 최대시간을 정수로 출력하여야한다. 만일 지연효과가 없으면 0을 출력해야하고, 도시를 빠져나가지 못하게 만들 수 있으면(지연시간이 무한대) -1을 출력해야 한다.
입력
첫 줄에는 지점의 수를 나타내는 정수 N(6 ≤ N ≤ 1000)과 도로의 수 M(6 ≤ M ≤ 5000)이 주어진다. 그 다음 이어 나오는 M개의 각 줄에는 도로(a, b)와 그 통과시간 t가 a b t 로 표시된다. 단 이 경우 a < b 이고 1 ≤ t ≤ 10000이다.
출력
경찰이 하나의 도로를 막음으로써 지연시킬 수 있는 최대 시간을 정수로 출력한다. (단, 그 지연시간이 무한대이면 -1을 출력해야 한다.)
2. 코드
import sys
from heapq import heappush, heappop
inp = lambda: map(int, sys.stdin.readline().split())
INF = sys.maxsize
# 다익스트라 함수
def dijstra(s, e):
dis = [INF] * (n + 1)
dis[1] = 0
queue = []
heappush(queue, (0, 1))
while queue:
dist, now = heappop(queue)
if dis[now] < dist:
continue
for i in maps[now]:
cost = dist + i[1]
# 도로 검문으로 막기 위한 if절!! 양 방향 이므로 출발지, 도착지 를 두개다 판별해야한다.
if s == now and e == i[0] or s == i[0] and e == now:
continue
if cost < dis[i[0]]:
dis[i[0]] = cost
near[i[0]] = now
heappush(queue, (cost, i[0]))
return dis
n, m = inp()
# 입력
maps = [[] for _ in range(n + 1)]
# 최소 비용 으로 가기 위한 루트가 어딘지 파악 하기 위한 배열
near = [0] * (n + 1)
# 입력
for _ in range(m):
# 양방향
a, b, c = inp()
maps[a].append((b, c))
maps[b].append((a, c))
# 검문 없이 최초 최소 비용 가는법
S = dijstra(0, 0)
# 정답 을 위한
ans = -1
# 부모 루트, 즉 최소 비용으로 가기 위해 들렸던 곳을 역으로 도출하기 위한 변수
k = n
# 도착 지점이 출발 했던 곳이 아니라면 무한 루프
while not k == 1:
# 최소 비용으로 들렸던 곳을 도로검문으로 막기 위함
s = near[k]
# s, k 길을 막고 난 후 최소비용 도출
dis = dijstra(s, k)
# 만약 목표지점(도착)이 갈수 없는 곳이라면
if dis[n] == INF:
# 정답 출력
print(-1)
exit()
# 도착할수 있는 곳이라면 도로 검문으로 벌수 있는 최대 시간 도출
ans = max(ans, dis[n] - S[n])
k = s
print(ans)
3. 회고
Q. 문제를 보고 든 생각
- 입력 받았던 도로를 하나하나 제거해서 벌수 있는 최대 시간을 알아 내면 되겠다!! (바로 시간초과)..
- 문제의 핵심인 용의자가 목적지에 도달 하기 위해 최소비용으로 들렸던 곳을 도로 검문으로 막아 내면 되겠다 라는 생각을 하였다. (최소비용으로 들렸던 곳을 도출하는 문제로는 https://www.acmicpc.net/problem/11779) 이 문제가 있다.
- 이 문제를 먼저 해결 한 후 도로검문이라는 문제를 도전하게 되면 쉽게 풀릴것이다.
4. 고쳐야 할점
매일 한 문제 씩 풀어 나갈때 마다 그 전의 풀었던 문제의 의도를 정확하게 파악 한후 나의 것으로 만드는 것을 습관화 해야 될것 같다.(최소 비용으로 들렸던 곳을 도출하는방법을 순간적으로 떠오르지 않았다.. 물론 11779문제를 풀고도 말이다.)
'Algorithm > Python' 카테고리의 다른 글
백준 1202번 보석도둑 (0) | 2023.02.01 |
---|---|
프로그래머스 부대복귀 (0) | 2023.01.29 |
백준 1486번 등산 (0) | 2023.01.24 |
백준 22255번 호석사우루스 (0) | 2023.01.24 |
백준 2665번 미로만들기 (0) | 2023.01.23 |