일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- dynamic programming
- Algorithm
- hackerrank
- DP
- sw expert academy
- 시뮬레이션
- 브루트포스
- 그리디
- 다이나믹 프로그래밍
- 잠실
- 에라토스테네스의 체
- C++
- 맛집
- BOJ
- 완전탐색
- 소수
- 스택
- 삼성 기출
- dfs
- 해커랭크
- SWEA
- BFS
- koitp
- 구현
- 삼성 SDS 대학생 알고리즘 특강
- 동적 계획법
- 백트래킹
- PS
- 백준
- 알고리즘
- Today
- Total
펭로그
[C++] 백준 BOJ 2805 나무 자르기 본문
문제링크 : https://boj.kr/2805
1. 동적계획법(DP)을 이용한 풀이법 : 시간복잡도 O(N)
나무의 길이가 제일 큰 것부터 시작하여 한단계씩 내려오면서 누적 합이 입력에서 주어진 값보다 클 때까지 구하는 방법으로 풀었다.
입력 받은 값들을 내림차순으로 정렬하고 맨 첫번째 인덱스에 해당하는 값부터 시작하여 1씩 높이를 빼가면서 계산했다.
나무의 높이(arr[N])가 기준 높이(result)보다 높은 부분 까지만 인덱스를 탐색하고 기준 높이 이하(arr[N] - result)가 0 이하인 값들)가 나오면 현재 누적 잘린 나무들의 합이 정답보다 작다면 계속 루프를 진행한다.
이때, 높이를 1씩 빼게되면 현재까지 진행해왔던 나무들의 높이가 각각 1씩 추가되기 때문에 sum += ptr 구문을 넣어 더해줬다.
그림으로 설명하자면 아래와 같이 설명할 수 있다.
회색은 이전 루프에서 누적된 값 (sum)
노란색은 현재 루프에서 누적된 값 (sum += arr[ptr++] - result)
초록색은 다음 루프로 넘어갈 때 추가되는 값 (sum += ptr)
여기서 노란색 ptr은 루프 끝나는 부분의 인덱스이며
초록색 ptr은 루프 시작 부분의 인덱스를 의미한다.
++이 후위연산(postfix)이기 때문에 현재 루프를 탈출하기 전에는 노란색 인덱스, 다음 루프때 ++이 되어 초록색 인덱스가 된다.
(답이 나올 때까지 반복)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // BOJ 2805 나무 자르기 #include <iostream> #include <algorithm> #include <vector> #include <functional> using namespace std; int main() { // freopen("input.txt", "r", stdin); ios_base::sync_with_stdio(false); int num, legnth; cin >> num >> legnth; vector<int> arr(num); for (int i = 0; i < num; i++) cin >> arr[i]; sort(arr.begin(), arr.end(), greater<int>()); int sum = 0; int result = arr.front() - 1; int ptr = 0; while (true) { while (arr[ptr] - result > 0) sum += arr[ptr++] - result; if (sum < legnth) { result--; sum += ptr; } else { break; } } cout << result; return 0; } | cs |
2. 이진탐색(Binary Search)를 추가로 적용한 풀이법 : 시간복잡도 O(logN)
위에서 정답을 찾기 위해서 맨 큰 숫자부터 시작하여 1씩 줄여가면서 찾았기 때문에 최악의 경우는 N번을 모두 실행해야 하기 때문에 O(N)임을 알 수 있다.
하지만, 이진탐색 기법을 추가로 적용한다면 정답의 가능성이 있는 부분만 취하고 나머지 절반은 버리는 식으로 계속 탐색을 하기 때문에 탐색 횟수를 훨씬 줄일 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | // BOJ 2805 나무 자르기 #include <iostream> #include <algorithm> #include <vector> #include <functional> using namespace std; int main() { // freopen("input.txt", "r", stdin); ios_base::sync_with_stdio(false); int num, length; cin >> num >> length; vector<int> arr(num); for (int i = 0; i < num; i++) cin >> arr[i]; sort(arr.begin(), arr.end(), greater<int>()); int top = arr.front(); int mid = 0; int btm = 0; int result = 0; while (btm < top) { long long sum = 0; mid = (top + btm) / 2; for (int i = 0; i < num && arr[i] - mid > 0; i++) sum += arr[i] - mid; if (sum < length) { top = mid; } else { result = mid; btm = mid + 1; } } cout << result; return 0; } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // BOJ 2805 나무 자르기 #include <iostream> #include <vector> using namespace std; int main() { // freopen("input.txt", "r", stdin); ios_base::sync_with_stdio(false); int num, length; cin >> num >> length; vector<int> arr(num); int top = 0; int mid = 0; int btm = 0; int result = 0; for (int i = 0; i < num; i++) { cin >> arr[i]; top = max(top, arr[i]); } while (btm < top) { long long sum = 0; mid = (top + btm) / 2; for (int i = 0; i < num; i++) if(arr[i] - mid > 0) sum += arr[i] - mid; if (sum < length) { top = mid; } else { result = mid; btm = mid + 1; } } cout << result; return 0; } | cs |
'Study > PS(Algorithm)' 카테고리의 다른 글
[C++] 백준 BOJ 7562 나이트의 이동 (0) | 2018.09.14 |
---|---|
[C++] 백준 BOJ 9465 스티커 (0) | 2018.09.13 |
[C++] 백준 BOJ 2110 공유기 설치 (실패) (0) | 2018.09.07 |
[C++] 백준 BOJ 2293 동전1 (0) | 2018.09.04 |
[C++] BOJ 백준 1463 1로 만들기 (0) | 2018.09.01 |