1446 swift / c++ - 지름길
2024. 10. 4. 07:42ㆍ🐣/BOJ
다이나믹프로그래밍과 다익스트라 두 방법 모두 사용할 수 있습니다.
시간 복잡도
- 시간 복잡도는 O(D + N)입니다.
- D는 고속도로의 길이, N은 지름길의 수입니다.
- 문제에서 N ≤ 12, D ≤ 10,000이므로, 이 접근 방식은 충분히 효율적입니다.
C++ DP 풀이.
#include <bits/stdc++.h>
using namespace std;
#define INF 1e9
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, d;
cin >> n >> d;
vector<pair<int, int>> graph[10001];
for (int i = 0; i < n; i++) {
int from, to, cost;
cin >> from >> to >> cost;
if (to <= d) {
graph[from].push_back({to, cost});
}
}
vector<int> dist(d + 1, INF);
dist[0] = 0;
for (int i = 0; i <= d; i++) {
if (i > 0) {
dist[i] = min(dist[i], dist[i - 1] + 1);
}
for (auto& g : graph[i]) {
int next = g.first;
int cost = g.second;
if (dist[next] > dist[i] + cost) {
dist[next] = dist[i] + cost;
}
}
}
cout << dist[d];
return 0;
}
import Foundation
let nd = readLine()!.split(separator: " ").map{Int(String($0))!}
let (n, d) = (nd[0], nd[1])
var graph = [[(Int, Int)]](repeating: [], count: d + 1)
for _ in 0..<n {
let shortcut = readLine()!.split(separator: " ").map{Int(String($0))!}
let from = shortcut[0], to = shortcut[1], cost = shortcut[2]
if to <= d {
graph[from].append((to, cost))
}
}
var dist = [Int](repeating: Int.max, count: d + 1)
dist[0] = 0
for i in 0...d {
if i > 0 {
dist[i] = min(dist[i], dist[i - 1] + 1)
}
for (next, cost) in graph[i] {
if next <= d {
dist[next] = min(dist[next], dist[i] + cost)
}
}
}
print(dist[d])
다익스트라 알고리즘과 DP의 차이점
- 동적 계획법 (DP) 방식은 각 지점에서 순차적으로 거리를 갱신하면서 최단 거리를 찾습니다. 이 방식은 모든 지점을 방문하며 각 지름길을 업데이트하는 방식으로 구현됩니다.
- 다익스트라 알고리즘은 우선순위 큐를 사용하여 현재 최단 거리가 작은 지점부터 탐색합니다. 따라서 최적의 경로를 더 빨리 찾기 위한 탐색 순서의 최적화가 가능합니다.
- 이 문제에서 두 방법 모두 사용이 가능하지만, 다익스트라 알고리즘은 일반적으로 더 많은 정점이 존재하고 가중치가 다양한 경우 더 효율적으로 작동합니다.
시간 복잡도
- 다익스트라 알고리즘의 시간 복잡도는 O((V + E) * log V)입니다.
- V는 정점의 개수 (D), E는 간선의 개수 (N)입니다.
- 우선순위 큐를 사용하는 경우, 각 정점 및 간선의 업데이트가 로그 시간에 수행됩니다.
- 이 문제에서는 N ≤ 12, D ≤ 10,000이기 때문에, 다익스트라의 시간 복잡도는 충분히 효율적입니다.
결론
- DP 방식과 다익스트라 알고리즘 모두 이 문제에서 사용될 수 있습니다.
- DP 방식은 각 위치에서 가능한 모든 경로를 반복적으로 갱신하는 방식이며, 다익스트라 알고리즘은 우선순위 큐를 사용하여 현재 가능한 최단 경로를 효율적으로 찾아갑니다.
- 다익스트라 방식은 더 많은 정점과 간선이 있을 때 효율적으로 작동하며, 우선순위 큐를 사용하여 최적의 정점을 빠르게 선택합니다.
c++ 다익스트라 풀이
#include <bits/stdc++.h>
using namespace std;
#define INF 1e9
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, d;
cin >> n >> d;
vector<pair<int, int>> graph[10001];
for (int i = 0; i < n; i++) {
int from, to, cost;
cin >> from >> to >> cost;
if (to <= d) {
graph[from].push_back({to, cost});
}
}
// 다익스트라를 위한 최소 힙 선언 (거리, 정점) 형태로 저장
priority_queue<pair<int, int>, vector<pair<int, int>>,
greater<pair<int, int>>>
pq;
// 최단 거리 배열 초기화
vector<int> dist(d + 1, INF);
dist[0] = 0;
pq.push({0, 0}); // (거리, 시작 위치)
// 다익스트라 알고리즘
while (!pq.empty()) {
int currentDist = pq.top().first;
int currentNode = pq.top().second;
pq.pop();
// 이미 처리된 거리보다 큰 경우는 무시
if (currentDist > dist[currentNode]) {
continue;
}
// 직선 도로로 이동 (다음 1km)
if (currentNode + 1 <= d && dist[currentNode + 1] > currentDist + 1) {
dist[currentNode + 1] = currentDist + 1;
pq.push({dist[currentNode + 1], currentNode + 1});
}
// 현재 노드에서 출발하는 지름길 처리
for (auto& shortcut : graph[currentNode]) {
int nextNode = shortcut.first;
int shortcutCost = shortcut.second;
if (dist[nextNode] > currentDist + shortcutCost) {
dist[nextNode] = currentDist + shortcutCost;
pq.push({dist[nextNode], nextNode});
}
}
}
cout << dist[d] << "\n";
return 0;
}
Swift Priority Queue
더보기
struct Heap<T> {
var elements: [T] = []
let priorityFunction: (T, T) -> Bool
init(priorityFunction: @escaping (T, T) -> Bool) {
self.priorityFunction = priorityFunction
}
var isEmpty: Bool {
return elements.isEmpty
}
func peek() -> T? {
return elements.first
}
mutating func remove() -> T? {
guard !elements.isEmpty else {
return nil
}
if elements.count == 1 {
return elements.removeFirst()
} else {
let value = elements.first
elements[0] = elements.removeLast()
siftDown(elementAtIndex: 0)
return value
}
}
mutating func push(_ element: T) {
elements.append(element)
siftUp(elementAtIndex: elements.count - 1)
}
mutating func pop() -> T? {
guard !isEmpty else {
return nil
}
elements.swapAt(0, elements.count - 1)
let poppedElement = elements.removeLast()
siftDown(elementAtIndex: 0)
return poppedElement
}
private mutating func siftUp(elementAtIndex index: Int) {
let parent = parentIndex(of: index)
guard !isRoot(index), priorityFunction(elements[index], elements[parent]) else {
return
}
elements.swapAt(index, parent)
siftUp(elementAtIndex: parent)
}
private mutating func siftDown(elementAtIndex index: Int) {
let childIndex = highestPriorityIndex(for: index)
if index == childIndex {
return
}
elements.swapAt(index, childIndex)
siftDown(elementAtIndex: childIndex)
}
private func isRoot(_ index: Int) -> Bool {
return index == 0
}
private func leftChildIndex(of index: Int) -> Int {
return 2 * index + 1
}
private func rightChildIndex(of index: Int) -> Int {
return 2 * index + 2
}
private func parentIndex(of index: Int) -> Int {
return (index - 1) / 2
}
private func highestPriorityIndex(for parent: Int) -> Int {
let leftChild = leftChildIndex(of: parent)
let rightChild = rightChildIndex(of: parent)
var highest = parent
if leftChild < elements.count && priorityFunction(elements[leftChild], elements[highest]) {
highest = leftChild
}
if rightChild < elements.count && priorityFunction(elements[rightChild], elements[highest]) {
highest = rightChild
}
return highest
}
}
Swift 다익스트라
더보기
let nd = readLine()!.split(separator: " ").map{Int(String($0))!}
let (n, d) = (nd[0], nd[1])
var graph = [[(Int, Int)]](repeating: [], count: d + 1)
for _ in 0..<n {
let shortcut = readLine()!.split(separator: " ").map{Int(String($0))!}
let from = shortcut[0], to = shortcut[1], cost = shortcut[2]
if to <= d {
graph[from].append((to, cost))
}
}
var dist = [Int](repeating: Int.max, count: d + 1)
dist[0] = 0
var pq = Heap<(Int, Int)>(priorityFunction: {$0.0 < $1.0})
pq.push((0, 0))
while !pq.isEmpty {
let (currentDist, currentNode) = pq.pop()!
if currentDist > dist[currentNode] {
continue
}
if currentNode + 1 <= d && dist[currentNode + 1] > currentDist + 1 {
dist[currentNode + 1] = currentDist + 1
pq.push((dist[currentNode + 1], currentNode + 1))
}
for (nextNode, cost) in graph[currentNode] {
if dist[nextNode] > currentDist + cost {
dist[nextNode] = currentDist + cost
pq.push((dist[nextNode], nextNode))
}
}
}
print(dist[d])
'🐣 > BOJ' 카테고리의 다른 글
16235 c++ - 나무 재테크 (12) | 2024.10.08 |
---|---|
1299 c++ - 전쟁-탈출편2 (0) | 2024.10.05 |
18352 swift - 특정 거리의 도시 찾기 (0) | 2024.10.02 |
12100 swift / c++ - 2048 (Easy) (0) | 2024.09.23 |
6603 swift - 로또 (0) | 2024.04.28 |