📖 백준 1238번 : https://www.acmicpc.net/problem/1238

N개의 숫자로 구분된 각각의 마을에 한 명의 학생이 살고 있다.
어느 날 이 N명의 학생이 X (1 ≤ X ≤ N)번 마을에 모여서 파티를 벌이기로 했다. 이 마을 사이에는 총 M개의 단방향 도로들이 있고 i번째 길을 지나는데 Ti(1 ≤ Ti ≤ 100)의 시간을 소비한다.
각각의 학생들은 파티에 참석하기 위해 걸어가서 다시 그들의 마을로 돌아와야 한다. 하지만 이 학생들은 워낙 게을러서 최단 시간에 오고 가기를 원한다.
이 도로들은 단방향이기 때문에 아마 그들이 오고 가는 길이 다를지도 모른다. N명의 학생들 중 오고 가는데 가장 많은 시간을 소비하는 학생은 누구일지 구하여라.
첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어온다. 시작점과 끝점이 같은 도로는 없으며, 시작점과 한 도시 A에서 다른 도시 B로 가는 도로의 개수는 최대 1개이다.
모든 학생들은 집에서 X에 갈수 있고, X에서 집으로 돌아올 수 있는 데이터만 입력으로 주어진다.
첫 번째 줄에 N명의 학생들 중 오고 가는데 가장 오래 걸리는 학생의 소요시간을 출력한다.
최단경로 탐색을 수행해서 풀어낼 수 있는 문제다. 다익스트라 알고리즘을 알고 있다면 N번 반복해서 수행하더라도 제한 시간 안에 풀리는 쉬운 문제다.
모든 노드에서 X로 가는 최단 경로를 계산(N번 수행)하고 X에서 모든 노드로 가는 최단 경로(1번 수행)를 계산해서 가장 큰 값을 가지는 노드를 찾는다.
주어진 입력을 반대로 저장한 그래프를 통해서 X에서 모든 노드로 가는 최단 경로를 계산한다. 그 값이 곧, 모든 노드에서 X로 가는 최단 경로와 같다.
따라서 반대로 저장한 그래프로 X에서 모든 노드로 가는 최단 경로를 계산(1번 수행), X에서 모든 노드로 가는 최단 경로(1번 수행)를 계산해서 가장 큰 값을 가지는 노드를 찾을 수 있다.
위에서 올린 사진의 아래 부분이 1번 풀이로 제출한 결과이다. 시간이 116ms가 걸린 모습을 확인할 수 있다. 위의 부분은 2번 풀이로 제출한 결과이고 0ms가 걸린 모습을 확인할 수 있다.
문제를 풀때마다 드는 생각인데, 단순히 풀었다고 넘어가는 것이 아니라 자신의 생각을 다듬어보는 시간을 갖어야 더 성장할 수 있다고 생각한다. 또 더 좋은 풀이가 존재할 수 있으니 다른 사람들의 코드를 참고해 보는 것도 중요하다.
#include <iostream>
#include <queue>
#include <vector>
#define INF 999999999
using namespace std;
vector<int> dijkstra(int start, int vertex, vector<pair<int, int>>graph[]) {
vector<int> dist(vertex + 1, INF);
priority_queue<pair<int, int>> pq;
dist[start] = 0;
pq.push({ 0,start });
while (!pq.empty()) {
int cur_node = pq.top().second;
int cur_dist = -pq.top().first;//최소 힙을 음수로 저장하는 방식으로 구현
pq.pop();
if (dist[cur_node] < cur_dist) continue;
for (int i = 0; i < graph[cur_node].size(); i++) {
int nxt_node = graph[cur_node][i].first;
int nxt_dist = cur_dist + graph[cur_node][i].second;
if (dist[nxt_node] > nxt_dist) {
dist[nxt_node] = nxt_dist;
pq.push({ -nxt_dist, nxt_node });
}
}
}
return dist;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
vector <pair<int, int>> graph[1001];
int from, to, weight;
int V, E, x;
cin >> V >> E >> x;
for (int i = 0; i < E; i++) {
cin >> from >> to >> weight;
graph[from].push_back({ to, weight });
}
int distToX[1001];
for (int i = 1; i <= V; i++) {//노드의 개수만큼 경로찾기 반복
vector<int>dist = dijkstra(i, V, graph);
distToX[i] = dist[x];
}
vector<int> distFromX = dijkstra(x, V, graph);
int ans = 0;
for (int i = 1; i <= V; i++) //최대값 찾기
ans = max(ans, distToX[i] + distFromX[i]);
cout << ans;
return 0;
}
#include <iostream>
#include <queue>
#include <vector>
#define INF 999999999
using namespace std;
vector<int> dijkstra(int start, int vertex, vector<pair<int, int>>graph[]) {
vector<int> dist(vertex + 1, INF);
priority_queue<pair<int, int>> pq;
dist[start] = 0;
pq.push({ 0,start });
while (!pq.empty()) {
int cur_node = pq.top().second;
int cur_dist = -pq.top().first;
pq.pop();
if (dist[cur_node] < cur_dist) continue;
for (int i = 0; i < graph[cur_node].size(); i++) {
int nxt_node = graph[cur_node][i].first;
int nxt_dist = cur_dist + graph[cur_node][i].second;
if (dist[nxt_node] > nxt_dist) {
dist[nxt_node] = nxt_dist;
pq.push({ -nxt_dist, nxt_node });
}
}
}
return dist;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
vector <pair<int, int>> graph1[1001];
vector <pair<int, int>> graph2[1001];
int from, to, weight;
int V, E, x;
cin >> V >> E >> x;
for (int i = 0; i < E; i++) {
cin >> from >> to >> weight;
graph1[from].push_back({ to, weight });
graph2[to].push_back({ from,weight });//주어진 입력의 반대 방향으로 저장
}
vector<int> distToX = dijkstra(x, V, graph2);//graph2를 이용해서 한번의 계산으로 X로 가는 최단 경로를 구할 수 있다.
vector<int> distFromX = dijkstra(x, V, graph1);
int ans = 0;
for (int i = 1; i <= V; i++) //최대값 찾기
ans = max(ans, distToX[i] + distFromX[i]);
cout << ans;
return 0;
}