알고리즘 관련/BOJ
14938 서강그라운드
Andrew-Yun
2020. 12. 22. 19:40
처음에 이 문제를 접근할 때, 어려웠던 점은 양방향 그래프를 표현하는 방법이 헷갈렸다.
map과 2차원 배열 중에 어느 걸로 나타낼 지 고민하다 두 가지 방식을 다 해봤는데, map을 사용했을 때의 문제점은 한 정점과 다른 정점 사이의 최단 경로를 표현하기 애매했다.
그리고 DFS, BFS로 접근하려 했기 때문에 모든 정점들에 대해 탐색을 시도하려 했다. 하지만 그럴 필요 없이 이 문제에 딱 알맞는 알고리즘이 존재했는데, 플로이드 와샬 알고리즘이다.
플로이드 와샬 알고리즘을 사용하는건 다음과 같다.
- 모든 정점에서 다른 정점들까지 최단 경로를 알고 싶음
- 음수의 가중치를 갖는 간선에서의 최단 경로르 알고 싶음
단, 제약 조건도 있는데 다음과 같다.
- 음수 가중치를 갖는 사이클에서는 알고리즘의 정당성을 보장 못함
- 음의 무한대로 발산할 수 있기 때문에, 음수 사이클이 있는 경우엔 미리 검사해주어야 함
최단 경로를 찾는 알고리즘의 종류 중에 하나인 다익스트라와 비교했을 때, 다익스트라는 O(ElogV)의 시간 복잡도를 갖고, 모든 정점들에 대해 탐색한다면 O(V * ElogV)의 복잡도를 갖는다. 다만 구현이 조금 복잡하다.
반면, 플로이드는 O(V^3)의 복잡도를 갖는데 최단 경로 외에 모든 정점들을 탐색하기 때문이다.
이제 문제에 적용해보자. 문제의 요구조건은 탐색할 수 있는 범위 내의 아이템들의 최대 합이다. 다르게 말하면, 모든 정점 쌍들의 최단 경로들을 구한 후에 탐색 범위내의 정점이라면 모두 더한 값이 된다.
정답코드
더보기
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define MAX_SIZE 101
#define INF 987654321
int N, M, T[MAX_SIZE] = { 0, }, R;
int dist[MAX_SIZE][MAX_SIZE] = { {0,0} };
int ans = 0;
void setting()
{
for (int i = 1; i < MAX_SIZE; i++) {
for (int j = 1; j < MAX_SIZE; j++) {
if(i != j)
dist[i][j] = INF;
}
}
}
void floyd()
{
for (int k = 1; k <= N; k++) {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (dist[i][j] > dist[i][k] + dist[k][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
int main()
{
cin >> N >> M >> R;
for (int i = 1; i <= N; i++) {
cin >> T[i];
}
setting();
for (int i = 0; i < R; i++) {
int s, e, d;
cin >> s >> e >> d;
dist[s][e] = d;
dist[e][s] = d;
}
floyd();
for (int i = 1; i <= N; i++) {
int sum = T[i];
for (int j = 1; j <= N; j++) {
if (i == j)
continue;
if(dist[i][j] <= M)
sum += T[j];
}
ans = max(sum, ans);
}
printf("%d\n", ans);
return 0;
}