Optimal Solution
[백준, C++] 14719 - 빗물 본문
https://www.acmicpc.net/problem/14719
14719번: 빗물
첫 번째 줄에는 2차원 세계의 세로 길이 H과 2차원 세계의 가로 길이 W가 주어진다. (1 ≤ H, W ≤ 500) 두 번째 줄에는 블록이 쌓인 높이를 의미하는 0이상 H이하의 정수가 2차원 세계의 맨 왼쪽 위치
www.acmicpc.net
문제 분석
문제를 보자마자 최근 풀었던 한 문제가 생각났다. 아래에 그 문제를 풀고 작성한 포스트 링크를 첨부하겠다.
[백준, C++] 2304 - 창고 다각형
https://www.acmicpc.net/problem/2304 2304번: 창고 다각형 첫 줄에는 기둥의 개수를 나타내는 정수 N이 주어진다. N은 1 이상 1,000 이하이다. 그 다음 N 개의 줄에는 각 줄에 각 기둥의 왼쪽 면의 위치를 나타
optimal-solution.tistory.com
14719번 빗물 문제는 2304번 창고 다각형 문제와 매우 유사하다(첨부된 이미지까지도 유사하다). 그래서 창고 다각형 문제를 풀 때와 동일한 방법으로 풀 수 있을 것이라 생각했다.
가장 높은 블록을 기준으로 왼쪽과 오른쪽을 구분하고, 왼쪽에 고이는 빗물의 양과 오른쪽에 고이는 빗물의 양을 더하는 것이다.
코드
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int h, w;
int heights[500];
int result;
void getInput();
void solve();
void printResult();
int main() {
cin.tie(NULL);
ios::sync_with_stdio(false);
getInput();
solve();
printResult();
return 0;
}
void getInput() {
cin >> h >> w;
for (int i = 0; i < w; i++) {
cin >> heights[i];
}
}
void solve() {
int highestValue = 0;
int index = -1;
for (int i = 0; i < w; i++) {
if (highestValue < heights[i]) {
highestValue = heights[i];
index = i;
}
}
highestValue = heights[0];
for (int i = 1; i < index; i++) {
if (highestValue > heights[i]) {
result += highestValue - heights[i];
} else if (highestValue < heights[i]) {
highestValue = heights[i];
}
}
highestValue = heights[w - 1];
for (int i = w - 2; i > index; i--) {
if (highestValue > heights[i]) {
result += highestValue - heights[i];
} else if (highestValue < heights[i]) {
highestValue = heights[i];
}
}
}
void printResult() {
cout << result << "\n";
}
코드 설명
입력과 출력을 제외하고, solve() 부분만 설명하겠다. 사실 편의상 입력부(getInput()) / 풀이부(solve()) / 출력부(printResult())를 나누는 것인데(그러니까 문제 풀이 자체에만 집중하기 위해서 나누었다), 가장 높은 블록의 인덱스를 구하는 건 입력부에서 처리해도 되긴 하다. 하지만 풀이를 입출력과 분리하고 싶어 나는 나눴으니 그렇게 이해하고 설명을 보면 좋을 것 같다.
먼저 가장 높은 블록의 인덱스를 구한다. 그리고 이 인덱스를 index라는 변수에 할당한다.
다음으로 가장 높은 블록의 왼쪽에서 고인 빗물의 총량을 계산한다. 지금까지 가장 높은 블록의 높이(highestValue)를 heights[0]으로 지정하고, 인덱스 [1, index)를 순회한다. 그러면서 heights[i]가 highestValue보다 큰지, 작은지를 나눠 분기 처리한다. heights[i]가 highestValue보다 크다면, 즉 이전까지 나왔던 블록보다 더 높은 블록이 등장한 셈이므로 최고값을 갱신해준다. heights[i]가 highestValue보다 작다면, 여기는 highestValue까지 물이 고일 수 있다(그 원리는 index 위치에 가장 높은 블록이 있고, 따라서 물은 최대 highestValue까지 고일 수 있다는 뜻이기 때문임). 그래서 result에 (highestValue - heights[i])를 더해주게 된다. 이를 [1, index)까지 순회하면서 반복한다.
그리고 마지막으로, 가장 높은 블록의 오른쪽에서 고인 빗물의 총량을 계산한다. 지금까지 가장 높은 블록의 높이(highestValue)를 heights[w - 1]로 지정하고, 인덱스 (index, w - 1]을 역방향으로 순회한다. 그러면서 앞에서 했던 것처럼 heights[i]와 highestValue를 비교하며 빗물이 고인 양을 result에 추가하거나, highestValue 값을 갱신해준다.
최종적으로 우리는 가장 높은 블록의 왼쪽 / 오른쪽에 고인 빗물의 총량을 계산할 수 있게 된다.
(근데 왜 빗물 문제는 골드 문제고 창고 다각형 문제는 실버 문제일까 ? 풀이는 같은데 말이지)
'알고리즘' 카테고리의 다른 글
[백준, C++] 2467 - 용액 (0) | 2023.09.08 |
---|---|
[백준, C++] 5972 - 택배 배송 (0) | 2023.09.07 |
[백준, C++] 16234 - 인구 이동 (0) | 2023.09.06 |
[백준, C++] 20437 - 문자열 게임 2 (0) | 2023.09.06 |
[백준, C++] 20055 - 컨베이어 벨트 위의 로봇 (0) | 2023.09.06 |