dev_beomgeun
꾸준하게 차근차근
dev_beomgeun
전체 방문자
오늘
어제
  • 분류 전체보기 (170)
    • 전공 (0)
      • 운영체제 (0)
      • 알고리즘 (0)
      • 자료구조 (0)
      • 데이터베이스 (0)
      • 네트워크 (0)
    • 개발 공부 (32)
      • 웹 (6)
      • 리눅스 (4)
      • 머신러닝 (1)
      • 스프링 (17)
      • Git (2)
      • AWS (2)
    • 개발 도서, 강의 (3)
      • 스프링 입문을 위한 자바 객체지향의 원리와 이해 (0)
      • 모든 개발자를 위한 HTTP 웹 기본 지식(김영한.. (2)
      • 스프링 부트와 AWS로 혼자 구현하는 웹서비스 (1)
    • 문제 풀이 (118)
      • 백준 알고리즘 (72)
      • 프로그래머스 알고리즘, SQL (38)
      • Hackerrank SQL (8)
    • 프로젝트 기록 (4)
      • 캡스톤 종합설계 (4)
      • 반려하루 프로젝트 (0)
    • 활동 기록 (12)
      • 네이버 부스트캠프 (7)
      • 취준 & 코테 (4)
      • 소프트웨어 마에스트로 13기 (1)
    • 이것저것 (1)

블로그 메뉴

  • 홈
  • 깃허브
  • 링크드인
  • 방명록

공지사항

인기 글

태그

  • 네이버 부스트캠프
  • 프로그래머스
  • 백준
  • HackerRank mysql
  • Hackerrank
  • 스프링
  • 부스트캠프
  • BFS
  • c++
  • 반성
  • 프로그래머스 SQL
  • 서블릿
  • 그래프탐색
  • AI Tech
  • dp
  • 일기
  • 백준 DP
  • 회고
  • 기록
  • Baekjoon

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
dev_beomgeun

꾸준하게 차근차근

[baekjoon 14719] 빗물 (구현, 스택) (C++)
문제 풀이/백준 알고리즘

[baekjoon 14719] 빗물 (구현, 스택) (C++)

2021. 9. 24. 19:12
728x90

https://www.acmicpc.net/problem/14719

 

14719번: 빗물

첫 번째 줄에는 2차원 세계의 세로 길이 H과 2차원 세계의 가로 길이 W가 주어진다. (1 ≤ H, W ≤ 500) 두 번째 줄에는 블록이 쌓인 높이를 의미하는 0이상 H이하의 정수가 2차원 세계의 맨 왼쪽 위치

www.acmicpc.net

2차원 세계에 블록이 쌓여있다. 비가 오면 블록 사이에 빗물이 고인다.

이런 식으로 빗물이 고인다. 

 

아이디어를 찾는다면 나름 쉽게 풀 수 있다.

 

1. 시뮬레이션, 구현

 

5 4 3 5 6 8 7 1 이 있다고 치면 빗물은 좌, 우에 쌓일 것이다. 그러므로 4부터 계산을 해주는데

4는 5와 8 사이에 있고 틈에 총 1만큼 쌓일 것이다.

3은 5와 8 사이에 있고 틈에 총 2만큼 쌓일 것이다.

5, 6, 8, 7, 1은 빗물이 쌓이지 못한다.

 

즉, 현재 나의 위치의 왼쪽과 오른쪽에서 가장 큰 수와 나를 비교해서 두 수 보다 작으면, min(left, right) - 나 만큼 빗물이 찬다는 뜻이다.

아이디어를 잘 찾았다면 구현은 쉬울 것이다.

#include <iostream>
#include <stack>
#include <algorithm>

using namespace std;

stack<int> st;
int x, y, arr[501];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> x >> y;
	for (int i = 0; i < y; i++) {
		cin >> arr[i];
	}
	int answer = 0;

	for (int i = 1; i < y; i++) {
		int left = *max_element(arr, arr + i);
		int right = *max_element(arr + i + 1, arr + y);
		int cur = arr[i];
		if (cur < left && cur < right) {
			answer += min(left, right) - cur;
		}
	}
	cout << answer;
}

 

2. 스택

 

난 처음에 스택을 이용해서 풀었는데, 식이 꽤나 복잡해졌다.

간단하게 설명하면, 스택의 내부는 top으로 갈수록 작거나, 같도록 유지해주었다.

그리고 top보다 큰 수가 들어오면 pop 해주면서 더해주었다.

 

3 0 1 이 들어오면 스택은 3이 들어오고, 0이 들어오고 (top이 더 작으므로 push)

이후 1이 들어오면(top보다 크므로 차이만큼 더해준다.) 1-0만큼 더해주었다.

 

하지만 이렇게 pop 하고 끝내버린다면 3 0 1 4의 경우 3과 4 사이에 총 5만큼 쌓여야 하는데

0이 pop 되었으므로 0에 해당하는 추가 depth 2를 더해주지 못한다.

따라서 난 pop 한 만큼 개수를 세서 다시 업데이트해서 넣어주었다.

 

3 0 1 4에서 1을 만났을 경우, top은 0이므로 pop해준 뒤 pop 한 개수만큼 1을 넣어준다.

즉, 더해준 만큼 틈을 채워준다고 생각하면 된다.

그러면 스택 내부는 3 1 1이 되어있을 것이고, 그때 4를 만나면 3을 만날 때까지 3-1, 3-1이 더해져서 총 5가 된다.

위에서 왜 4-1이 아니고 3-1을 했냐 하면 분기를 나눠줘야 하기 때문이다.

 

0. 스택에 수를 쌓으면서 최댓값을 저장해준다. (3 0 1의 경우 3을 최댓값으로 기억하고 있자)

1. top보다 수가 적으면 push

2. top보다 수가 크면 

2-1. 만약 들어오는 수가 최대와 같다면

=> 최대 높이 사이의 수들에 대해서 계산을 해준다 3 0 1 3이면 0 1에 해당, 그리고 0 1을 3만큼 채웠으므로 3 3 3 3

2-2. 만약 들어오는 수가 최대보다 크다면

=> 최대 높이 사이의 수들에 대해서 계산을 해준다 3 0 1 4면 0 1에 해당, 그리고 4보다 작으므로 3 0 1은 더 이상 틈을 채울 수 없으므로 그냥 pop 해준다. (이후의 높이는 4에 맞춰서 계산되므로)

2-3. 만약 들어오는 수가 최대보다 적다면

=> 들어오는 수보다 작은 수를 만날 때까지 수를 처리해준다. 3 0 1 2면 0 1에 해당, 3 2 2 2 가 된다.

 

#include <iostream>
#include <stack>

using namespace std;

stack<int> st;
int x, y, arr[501];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> x >> y;
	for (int i = 0; i < y; i++) {
		cin >> arr[i];
	}

	int limit = 0, answer = 0;
	for (int i = 0; i < y; i++) {
		int height = arr[i];
		if (st.empty()) { // 제일 처음 초기화 과정
			st.push(height);
			limit = max(limit, st.top());
		}
		else {
			if (height <= st.top()) { // top보다 작거나 같으면 그냥 push
				st.push(height);
			}
			else { // height이 st.top() 보다 크면
				if (height == limit) { // 그때 현재 수가 이제까지의 최대와 같으면 
					int cnt = 1;
					while (st.top() != height) { // 최대까지 가면서 그 차이를 더해준다.
						cnt++;
						answer += height - st.top();
						st.pop();
					}
					for (int i = 0; i < cnt; i++) // 틈을 채운 수로 업데이트
						st.push(height);
				}
				else if (height > limit) { // 현재 수가 최대보다 크면
					while (st.top() < height) { // 현재 수보다 작은 수는 다 빼준다.
						answer += limit - st.top(); // 차이는 최대와 st.top
						st.pop();
						if (st.empty())
							break;
					}
					limit = height; // 현재 수보다 작은 수를 다 빼줬으므로 새롭게 갱신해준다.
					st.push(height);
				}
				else { // height이 limit 보다 작으면
					int cnt = 1; // 기본 height 넣을 갯수
					while (st.top() < height) {
						cnt++;
						answer += height - st.top();
						st.pop();
					}
					for (int i = 0; i < cnt; i++)
						st.push(height);
				}
			}
		}
	}
	cout << answer;
}

스택 풀이는 해로운 것 같다.. 코드를 보고도 이해가 될까 싶긴 하다.

 

728x90
저작자표시 비영리 변경금지 (새창열림)

'문제 풀이 > 백준 알고리즘' 카테고리의 다른 글

[baekjoon 22860] 폴더 정리(small) (DFS, BFS, 구현, HashMap) (C++)  (0) 2021.10.05
[baekjoon 14503] 로봇 청소기 (구현, 시뮬레이션) (C++)  (0) 2021.09.24
[baekjoon 19951] 태상이의 훈련소 생활 (누적합) (C++)  (0) 2021.09.21
[baekjoon 3190] 뱀 (덱, 시뮬레이션) (C++)  (0) 2021.09.21
[baekjoon 2800] 괄호 제거 (스택, 구현, 재귀) (C++)  (0) 2021.09.20
    '문제 풀이/백준 알고리즘' 카테고리의 다른 글
    • [baekjoon 22860] 폴더 정리(small) (DFS, BFS, 구현, HashMap) (C++)
    • [baekjoon 14503] 로봇 청소기 (구현, 시뮬레이션) (C++)
    • [baekjoon 19951] 태상이의 훈련소 생활 (누적합) (C++)
    • [baekjoon 3190] 뱀 (덱, 시뮬레이션) (C++)
    dev_beomgeun
    dev_beomgeun
    백엔드 개발을 하며 얻은 지식과 경험을 공유합니다. 현재 카카오페이에서 백엔드 엔지니어로 일하고 있습니다.

    티스토리툴바