Link
https://www.acmicpc.net/problem/10473
Detail
처음엔 기하학 문제로 접근했으나, 고민을 거친후에 (시작점, 목적지, 각 대포) 를 하나의 정점으로, 각 정점사이 간선의 가중치는 (이동에 걸리는 최적 시간)으로 계산하여 그래프를 세운다면 다익스트라로 바로 해결이 가능하다고 보였다.
Code
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
double getDist(const pair<double, double>& a, const pair<double, double>& b) {
double first_diff = (a.first - b.first) * (a.first - b.first);
double second_diff = (a.second - b.second) * (a.second - b.second);
return sqrt(first_diff + second_diff);
}
struct Edge {
int to;
double weight;
};
double calculateWeight(double dist) {
double cannon_time = abs(dist - 50.0) / 5.0 + 2;
double walk_time = dist / 5.0;
return min(cannon_time, walk_time);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
pair<double, double> start, dest;
cin >> start.first >> start.second;
cin >> dest.first >> dest.second;
int n;
cin >> n;
vector<pair<double, double>> points(n);
for (int i = 0; i < n; i++) {
cin >> points[i].first >> points[i].second;
}
// 그래프 구성
vector<vector<Edge>> graph(n + 2); // 시작점 + 목적지 + 중간점들
// 시작점과 목적지를 포함한 간선 추가
// 시작점 -> 각 대포
for (int i = 0; i < n; i++) {
double dist = getDist(start, points[i]);
graph[0].push_back({ i + 1, dist / 5.0 });
}
// 시작점 -> 목적지 그냥 걷기
graph[0].push_back({ n + 1, getDist(start, dest) / 5.0 });
// 대포 사이 간선 추가
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double dist = getDist(points[i], points[j]);
double weight = calculateWeight(dist);
graph[i + 1].push_back({ j + 1, weight });
graph[j + 1].push_back({ i + 1, weight });
}
}
// 대포 -> 목적지
for (int i = 0; i < n; i++) {
double dist = getDist(points[i], dest);
graph[i + 1].push_back({ n + 1, calculateWeight(dist) });
}
// 다익스트라 알고리즘
vector<double> dist(n + 2, numeric_limits<double>::infinity());
dist[0] = 0.0;
priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;
pq.push({ 0.0, 0 });
while (not pq.empty()) {
double d = pq.top().first;
int u = pq.top().second;
pq.pop();
if (d > dist[u]) continue;
for (const auto& edge : graph[u]) {
int v = edge.to;
double weight = edge.weight;
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({ dist[v], v });
}
}
}
// 결과 출력
cout << dist[n + 1] << "\n";
return 0;
}