반응형
문제 출처 :
https://www.acmicpc.net/problem/6549
알고리즘 분석 :
문제 해결에 필요한 사항
1. 세그먼트 트리(Segment Tree) :: http://www.crocus.co.kr/648
세그먼트 트리를 이용하여 O(nlgn)에 해결 할 수 있는 문제이다.
이 문제를 이렇게 접할 수 있다는 것을 배우고 나서 매우 신기하였고, 세그먼트 트리를 배운 입장에서 응용 단계에는 아직 많이 못 미치는듯 하다.
init과정에서는 아래와 같이 세그먼트 트리의 리프 노드에는 인덱스 번호를, 그리고 그 위의 노드 부터는 그 구간에 해당하는 최소 높이에 해당하는 인덱스를 넣어준다.
(아래 댓글을 통해 수정하였습니다. 아래 그림상에서 리프노드가 아닌곳에 최소 높이가 다 적혀있는데 그게 아닌 최소 높이가 있는 인덱스가 있어야 합니다.)
그다음 아래와 같이 붉은색 내용 중 최소를 찾는 과정이 query 과정이고,
그 최솟값을 이용하여 start(s)와 end(e)를 이용하여 넓이를 구하는 과정이 getMax 과정이다.
세그 트리를 공부하고 스택이 아닌 세그 트리로 접근해보면 매우 흥미로운 문제인 것 같다.
소스 코드 :
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <algorithm> using namespace std; typedef long long ll; void init(vector<int> &arr, vector<int> &tree, int node, int start, int end) { // start와 end가 같으면 리프 노드. 이때 node에 start idx를 넣는다. if (start == end) tree[node] = start; // start와 end가 다르다면 else { int mid = (start + end) / 2; init(arr, tree, node * 2, start, mid); init(arr, tree, node * 2 + 1, mid + 1, end); // 각 구간에서 가장 높이가 낮은 것을 노드에 넣어준다. if (arr[tree[node * 2]] <= arr[tree[node * 2 + 1]]) tree[node] = tree[node * 2]; else tree[node] = tree[node * 2 + 1]; } } // 구간에서 가장 최소인 높이의 막대 구하기 int query(vector<int> &arr, vector<int> &tree, int node, int start, int end, int left, int right) { if (left > end || right < start) return -1; if (left <= start && end <= right) return tree[node]; int mid = (start + end) / 2; int m1 = query(arr, tree, node * 2, start, mid, left, right); int m2 = query(arr, tree, node * 2 + 1, mid + 1, end, left, right); if (m1 == -1) return m2; else if (m2 == -1) return m1; else { if (arr[m1] <= arr[m2]) return m1; else return m2; } } ll getMax(vector<int> &arr, vector<int> &tree, int start, int end) { int n = arr.size(); int m = query(arr, tree, 1, 0, n - 1, start, end); // 넓이 계산 ll area = (ll)(end - start + 1)*(ll)arr[m]; // 왼쪽 막대가 존재하냐? if (start <= m - 1) { ll tmp = getMax(arr, tree, start, m - 1); if (area < tmp) area = tmp; } // 오른쪽 막대가 존재하나? if (m + 1 <= end) { ll tmp = getMax(arr, tree, m + 1, end); if (area < tmp) area = tmp; } // 최대 넓이 반환 return area; } int main() { while (1) { int n; scanf("%d", &n); if (n == 0) break; vector<int> arr(n); // 값을 입력 받는다. for (int i = 0; i < n; i++) scanf("%d", &arr[i]); // 세그 트리 크기를 구한다. int h = (int)(ceil(log2(n))+1e-9); int tree_size = (1 << (h + 1)); vector<int> tree(tree_size); // 세그 트리 형성 init(arr, tree, 1, 0, n - 1); printf("%lld\n", getMax(arr, tree, 0, n - 1)); } return 0; } | Crocus |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[9466번] 텀 프로젝트 (0) | 2017.03.29 |
---|---|
[6603번] 로또 (7) | 2017.03.29 |
[1759번] 암호 만들기 (2) | 2017.03.28 |
[1162번] 도로포장 (7) | 2017.03.28 |
[2468번] 안전 영역 (0) | 2017.03.27 |