새소식

PS/백준

[백준/2325] 개코전쟁 (Python)

  • -

Problem : https://www.acmicpc.net/problem/2325

 

2325번: 개코전쟁

“앙두레 강”이 개미와 코끼리 결혼식에서 기차를 아름답게 만드는 것을 실패했기 때문에 식장이 아수라장이 되고 결혼이 물거품이 되어버렸다. 급기야는 왕국 간에 분쟁으로 이어져 개미왕

www.acmicpc.net

 

Difficulty : Platinum 5

 

Status : Solved

 

Time : 00:21:47

 


 

문제 설명

 

더보기

 

“앙두레 강”이 개미와 코끼리 결혼식에서 기차를 아름답게 만드는 것을 실패했기 때문에 식장이 아수라장이 되고 결혼이 물거품이 되어버렸다. 급기야는 왕국 간에 분쟁으로 이어져 개미왕국은 코끼리왕국을 공격하기로 결정하였다. 동물나라 지도에서 개미왕국은 1번 정점에 위치해 있고 코끼리왕국은 N번 정점에 위치해 있다. 따라서 개미왕국이 1번 정점에서 N번 정점으로 공격을 하러 가는 상황이다. (개미왕국은 최단거리로 이동을 하게 되고, 코끼리왕국은 움직이지 않는다)

“개미”와 “코끼리”의 앞 글자를 따서 이 전쟁은 “개코전쟁”으로 역사에 기억된다.

“앙두레 강”은 자신 때문에 발생한 이 전쟁을 어떻게든 막으려고 한다. 협상을 할 시간을 벌기 위해 개미왕국이 코끼리왕국에 도착하는 시간을 최대한 늦추려고 한다. 그래서 “앙두레 강”은 사자왕국의 도움을 빌어 도로 중 딱 하나를 파괴하려고 하는데 어느 도로를 파괴해야 개미왕국이 최단거리로 가더라도 그 거리를 최대로 할 수 있을까?

“앙두레 강”를 도와 1번 정점에서 N번 정점으로의 최단거리가 최대가 되도록 도로 하나를 파괴하도록 하자. (어떤 하나의 도로를 파괴하더라도 1번 정점에서 N번 정점으로 도달 가능하다)

 

 

입력 및 출력

 

더보기

입력

 

첫 줄에 N과 M이 입력된다. N은 정점의 개수이고 M은 도로의 수이다. (1 ≤ N ≤ 1000, 1 ≤ M ≤ N×(N-1)/2)

다음 줄부터 M개의 줄에 도로의 정보가 입력된다.

i+1번째 줄에는 i번째 도로의 정보 xi yi zi가 입력되고 이 도로는 정점 xi와 정점 yi를 잇는 도로이며 지나는데 zi만큼의 시간이 걸린다는 것을 의미한다. 두 정점사이에는 두 개 이상의 길이 존재하지 않고 모든 도로는 양방향이며 한 도로를 파괴하는 것은 양방향의 길 모두를 파괴하는 것이다. (1 ≤ xi, yi ≤ N, 1 ≤ zi ≤ 1000)

 

출력

 

적당한 도로하나를 파괴했을 때 1번 정점에서 N번 정점으로의 최단거리의 최댓값을 출력한다.

 

입력 예시

 

5 6
1 2 4
1 3 3
2 3 1
2 4 4
2 5 7
4 5 1

 

출력 예시

 

11

 

 


 

풀이

 

다익스트라 알고리즘으로 O(MlogN)의 시간복잡도 내에 최단 경로를 구할 수 있을 것이다. 개미 왕국은 항상 최단 경로로 움직이므로, 최단 경로상의 길이 아닌 다른 길을 삭제하더라도 최단 경로는 변화하지 않는다. 즉 우리는 최단 경로상의 임의의 길 하나를 삭제해야만 이 최단 경로가 변화함을 알 수 있다.

 

1번에서 N번까지의 최단 경로는 최대 N-1개의 경로를 거침을 알 수 있다. 즉 최대 N-1개의 경로를 삭제하고, 이 경로가 삭제되었을 때의 갱신된 최단 경로를 각각 구하여 최단거리를 최대로 수행할 수 있다. 이 때의 시간복잡도는 O(MNlogN)이 된다. 

 

풀이 코드

from collections import defaultdict
from heapq import *
import sys

input = sys.stdin.readline
MAX = float('inf')

N, M = map(int, input().split())
edge_dict = defaultdict(list)

for _ in range(M):
  a, b, c = map(int, input().split())
  edge_dict[a].append((b, c))
  edge_dict[b].append((a, c))
s, e = 1, N

def dijkstra(start, end, forbid=None):
  q = [(0, start)]
  dist = [(MAX, MAX)]*(N + 1)
  dist[start] = (0, start)
  while q:
    d, n = heappop(q)
    if dist[n][0] < d:
      continue
    if n == end:
      return dist, d
    for nxt, c in edge_dict[n]:
      if (n, nxt) == forbid or (nxt, n) == forbid:
        continue
      if dist[nxt][0] > d + c:
        dist[nxt] = (d + c, n)
        heappush(q, (d + c, nxt))

backtrack, _ = dijkstra(s, e)
ans = 0
node = e
while node != s:
  prev = backtrack[node][1]
  _, d = dijkstra(s, e, (prev, node))
  ans = max(ans, d)
  node = prev
print(ans)

풀이 완료!

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.