반응형

문제 출처 :


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 * + 1, mid + 1, end);
 
        // 각 구간에서 가장 높이가 낮은 것을 노드에 넣어준다.
        if (arr[tree[node * 2]] <= arr[tree[node * + 1]])
            tree[node] = tree[node * 2];
        else
            tree[node] = tree[node * + 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 * + 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, 10, 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 + <= 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 = (<< (h + 1));
 
        vector<int> tree(tree_size);
 
        // 세그 트리 형성
        init(arr, tree, 10, 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