[BOJ] 1238번 : 파티 (C++)

김우민·2024년 8월 1일

PS

목록 보기
4/34
post-thumbnail

📖 백준 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번 반복해서 수행하더라도 제한 시간 안에 풀리는 쉬운 문제다.

  1. 모든 노드에서 X로 가는 최단 경로를 계산(N번 수행)하고 X에서 모든 노드로 가는 최단 경로(1번 수행)를 계산해서 가장 큰 값을 가지는 노드를 찾는다.

  2. 주어진 입력을 반대로 저장한 그래프를 통해서 X에서 모든 노드로 가는 최단 경로를 계산한다. 그 값이 곧, 모든 노드에서 X로 가는 최단 경로와 같다.
    따라서 반대로 저장한 그래프로 X에서 모든 노드로 가는 최단 경로를 계산(1번 수행), X에서 모든 노드로 가는 최단 경로(1번 수행)를 계산해서 가장 큰 값을 가지는 노드를 찾을 수 있다.

 위에서 올린 사진의 아래 부분이 1번 풀이로 제출한 결과이다. 시간이 116ms가 걸린 모습을 확인할 수 있다. 위의 부분은 2번 풀이로 제출한 결과이고 0ms가 걸린 모습을 확인할 수 있다.

 문제를 풀때마다 드는 생각인데, 단순히 풀었다고 넘어가는 것이 아니라 자신의 생각을 다듬어보는 시간을 갖어야 더 성장할 수 있다고 생각한다. 또 더 좋은 풀이가 존재할 수 있으니 다른 사람들의 코드를 참고해 보는 것도 중요하다.

코드

  • 1번 풀이
#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;
}
  • 2번 풀이
#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;
}
profile
개발 일기

0개의 댓글