떡 돌리기
문제 해석
성현이가 N-1개의 집에 떡을 돌리기 위한 최소 일수를 구하는 문제입니다.
떡은 한번에 하나씩만 들고갈 수 있고, 하루에 X보다 먼 거리를 걷지 않고 가까운 집부터 방문합니다.
왕복할 수 없는 거리는 다음날 가기로 합니다.
설계(10)
간단하게 3가지 과정을 거치도록 설계하였습니다.
-
다익스트라 알고리즘을 사용하여 각 노드로 이동하기 위한 최단거리를 구합니다.O(MlogN) = O(10^6)
-
각 노드간 거리를 vector에 저장한 후, 거리가 짧은 순으로 정렬합니다.
-
loop문 두개를 사용하여 X/2보다 작거나 같을 때까지 떡을 돌리고 일수를 증가시키는 방식으로 모든 곳에 떡을 돌릴 때까지 반복합니다.
지문에서 모두 방문할 수 없을 시 -1을 출력하라고 되어있습니다. 그러면 방문을 못하는 경우는 아래와 같이 생각할 수 있을 것입니다.
-
성현이 집에서 아예 못가는 경로로 되어있는 경우
-
성현이가 하루에 왕복할 수 있는 거리보다 긴 경우
위의 두가지 경우를 고려하여 예외처리를 해주면 구현이 완료됩니다.
구현(15)
코드
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define MAXN 1000
vector<pair<int, int> > adj[MAXN];
int dist[MAXN];
vector<int> res;
priority_queue<pair<int, int> > pq;
int N, M, X, Y;
bool flag;
void dijkstra() {
pq.push({ 0,Y });
dist[Y] = 0;
while (!pq.empty()) {
int cur_dist = -pq.top().first;
int cur = pq.top().second;
pq.pop();
if (cur_dist != dist[cur]) continue;
for (int i = 0; i < adj[cur].size(); i++) {
int next = adj[cur][i].first;
int next_dist = adj[cur][i].second + cur_dist;
if (dist[next] == -1 || dist[next] > next_dist) {
dist[next] = next_dist;
pq.push({ -next_dist,next });
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
memset(dist, -1, sizeof(dist));
cin >> N >> M >> X >> Y;
while (M--) {
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back({ v,w });
adj[v].push_back({ u,w });
}
dijkstra();
for (int i = 0; i < N; i++) {
if (dist[i] == -1) {
cout << -1 << "\n";
return 0;
}
if (i == Y) continue;
res.push_back(dist[i]);
}
sort(res.begin(), res.end());
int idx = 0;
int day = 0;
while (idx < res.size()) {
int cur_dist = X/2;
while (idx < res.size() && cur_dist-res[idx]>= 0) {
cur_dist -= res[idx++];
}
if (cur_dist == X / 2) {
flag = true;
break;
}
day++;
}
if (flag) cout << -1 << "\n";
else cout << day << "\n";
return 0;
}
디버깅
제출결과
40 ms
마무리
다익스트라의 전형적인 문제였습니다. 하지만 해당 알고리즘외에 조건을 만족하는 일 수를 찾기 위해서 별도로 처리해주어야하는 부분이 있었습니다.