https://www.acmicpc.net/problem/1504
1504번: 특정한 최단 경로
첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존
www.acmicpc.net
다익스트라 알고리즘 문제. 마찬가지로 Rhyno님이 작성한 힙을 사용했다.
풀이
1번에서 n번 정점까지의 최단경로, 하지만 반드시 두지점을 거쳐야 한다는 조건이 붙었다.
[1 -> v1 -> v2 -> n ] 또는 [1 -> v2 -> v1 -> n] 두 가지 최단 경로중 가중치가 더 적은 경로를 반환하면 된다. 1번 정점에서 각 정점으로 향하는 최단경로, v1 정점에서 각 정점으로 향하는 최단경로, v2 정점에서 각 정점으로 향하는 최단경로 총 다익스트라 3번을 돌린 뒤 각 가중치를 적절히 조합해서 반환하면 된다.
하지만 여기서 경로가 없는 조건에 대해 처리해주어야 하므로 이 부분만 신경 써준다면 정답을 받을 수 있다. 본인의 경우 최단경로를 담은 배열을 -1로 초기화한뒤 다익스트라를 통해 갱신하였는데, 아무리 조건을 신경 써서 제출해도 오답판정을 받아 결국 계산 가능한 가중치의 최댓값인 2억으로 초기화하며 예외처리하였다.
정답 코드
import Foundation | |
//by rhyno | |
public struct Heap<T> { | |
var nodes: [T] = [] | |
let comparer: (T,T) -> Bool | |
var isEmpty: Bool { | |
return nodes.isEmpty | |
} | |
init(comparer: @escaping (T,T) -> Bool) { | |
self.comparer = comparer | |
} | |
func peek() -> T? { | |
return nodes.first | |
} | |
mutating func insert(_ element: T) { | |
var index = nodes.count | |
nodes.append(element) | |
while index > 0, !comparer(nodes[index],nodes[(index-1)/2]) { | |
nodes.swapAt(index, (index-1)/2) | |
index = (index-1)/2 | |
} | |
} | |
mutating func delete() -> T? { | |
guard !nodes.isEmpty else { | |
return nil | |
} | |
if nodes.count == 1 { | |
return nodes.removeFirst() | |
} | |
let result = nodes.first | |
nodes.swapAt(0, nodes.count-1) | |
_ = nodes.popLast() | |
var index = 0 | |
while index < nodes.count { | |
let left = index * 2 + 1 | |
let right = left + 1 | |
if right < nodes.count { | |
if comparer(nodes[left], nodes[right]), | |
!comparer(nodes[right], nodes[index]) { | |
nodes.swapAt(right, index) | |
index = right | |
} else if !comparer(nodes[left], nodes[index]){ | |
nodes.swapAt(left, index) | |
index = left | |
} else { | |
break | |
} | |
} else if left < nodes.count { | |
if !comparer(nodes[left], nodes[index]) { | |
nodes.swapAt(left, index) | |
index = left | |
} else { | |
break | |
} | |
} else { | |
break | |
} | |
} | |
return result | |
} | |
} | |
extension Heap where T: Comparable { | |
init() { | |
self.init(comparer: <) | |
} | |
} | |
let ne = readLine()!.split(separator: " ").map{Int($0)!} | |
let n = ne[0] | |
let e = ne[1] | |
var map = Array(repeating: [(Int,Int)](), count: n) | |
for _ in 0..<e{ | |
let info = readLine()!.split(separator: " ").map{Int($0)!} | |
let u = info[0]-1 | |
let v = info[1]-1 | |
let cost = info[2] | |
map[u].append((v,cost)) | |
map[v].append((u,cost)) | |
} | |
func dij(from a:Int) -> [Int]{ | |
var visited = Array(repeating: false, count: n) | |
var result = Array(repeating: 200000001, count: n) | |
var q = Heap<(Int,Int)>(comparer: { $0.1 > $1.1 }) | |
result[a] = 0 | |
q.insert((a,0)) | |
while !q.isEmpty{ | |
let curr = q.delete()! | |
let idx = curr.0 | |
if !q.isEmpty && visited[idx] { continue } | |
visited[idx] = true | |
for next in map[idx]{ | |
if result[next.0] > result[idx]+next.1{ | |
result[next.0] = result[idx]+next.1 | |
q.insert((next.0,result[next.0])) | |
} | |
} | |
} | |
return result | |
} | |
let targets = readLine()!.split(separator: " ").map{Int($0)!-1} | |
let curr = dij(from: 0) | |
let u = dij(from: targets[0]) | |
let v = dij(from: targets[1]) | |
var ans1 = curr[targets[0]] + u[targets[1]] + v[n-1] | |
var ans2 = curr[targets[1]] + v[targets[0]] + u[n-1] | |
var ans = min(ans1, ans2) | |
print(ans>=200000001 ? -1:ans) |

'Problem Solving > BOJ' 카테고리의 다른 글
[14246] K보다 큰 구간 (0) | 2023.01.12 |
---|---|
[2018] 수들의 합 5 (0) | 2023.01.11 |
[1238] 파티 (0) | 2023.01.04 |
[2056] 작업 (0) | 2023.01.02 |
[14567] 선수과목 (0) | 2023.01.01 |