Computer Science/Data Structure, Algorithm

Algorithm] KOI(한국정보올림피아드) 지역본선 - 탑

TwinParadox 2017. 5. 27. 00:00
728x90




KOI 통신연구소는 레이저를 이용한 새로운 비밀 통신 시스템 개발을 위한 실험을 하고 있다. 실험을 위하여 일직선 위에 N개의 높이가 서로 다른 탑을 수평 직선의 왼쪽부터 오른쪽 방향으로 차례로 세우고, 각 탑의 꼭대기에 레이저 송신기를 설치하였다. 모든 탑의 레이저 송신기는 레이저 신호를 지표면과 평행하게 수평 직선의 왼쪽 방향으로 발사하고, 탑의 기둥 모두에는 레이저 신호를 수신하는 장치가 설치되어 있다. 하나의 탑에서 발사된 레이저 신호는 가장 먼저 만나는 단 하나의 탑에서만 수신이 가능하다.

 

예를 들어 높이가 6, 9, 5, 7, 4인 다섯 개의 탑이 수평 직선에 일렬로 서 있고, 모든 탑에서는 주어진 탑 순서의 반대 방향(왼쪽 방향)으로 동시에 레이저 신호를 발사한다고 하자. 그러면, 높이가 4인 다섯 번째 탑에서 발사한 레이저 신호는 높이가 7인 네 번째 탑이 수신을 하고, 높이가 7인 네 번째 탑의 신호는 높이가 9인 두 번째 탑이, 높이가 5인 세 번째 탑의 신호도 높이가 9인 두 번째 탑이 수신을 한다. 높이가 9인 두 번째 탑과 높이가 6인 첫 번째 탑이 보낸 레이저 신호는 어떤 탑에서도 수신을 하지 못한다.

 

탑들의 개수 N과 탑들의 높이가 주어질 때, 각 각의 탑에서 발사한 레이저 신호를 어느 탑에서 수신하는지를 알아내는 프로그램을 작성하라.

 

첫째 줄에 탑의 수를 나타내는 정수 N이 주어진다. N1 이상 500,000 이하이다. 둘째 줄에는 N개의 탑들의 높이가 직선상에 놓인 순서대로 하나의 빈칸을 사이에 두고 주어진다. 탑들의 높이는 1 이상 100,000,000 이하의 정수이다.

 

첫째 줄에 주어진 탑들의 순서대로 각각의 탑들에서 발사한 레이저 신호를 수신한 탑들의 번호를 하나의 빈칸을 사이에 두고 출력한다. 만약 레이저 신호를 수신하는 탑이 존재하지 않으면 0을 출력한다.

 

 

EXAMPLE.INPUT)

5

6 9 5 7 4

 

EXAMPLE.OUTPUT

0 0 2 2 4

 

 

 

한국정보올림피아드시도지역본선 2009 > 초등부 4

한국정보올림피아드시도지역본선 2009 > 고등부 2



보자마자 두 가지 정도 구상이 가능하다.

직관적으로 봤을 땐 그냥 하나씩 전수조사 하는 방법이 있을 터.

전수조사를 하면 풀 수는 있지만 시간이 넉넉하다는 조건 하에 유효한 이야기고, 대부분의 알고리즘 대회에서는 시간과 할당 메모리에 제한을 두기 때문에 이런 전수 조사는 무의미하다. , 처음부터 제한을 안 거는 대회도 존재하지만, 결국 성능은 시간과 메모리를 얼마나 차지하느냐로 결정하기 때문에...

 

다시 한 번 생각해보면 뭔가 스택을 써야 될 것 같다는 걸 암시해주는 부분이 있다.

레이저가 일방향성으로 진행하는데 이를 수신할 수 있는 건 송신탑보다 크거나 같은 높이의 수신탑의 경우다. 그러니까, 레이저를 수신할 수 있는 수신탑이 나타나는 순간 수신탑 너머에 무엇이 있든 의미가 없다는 뜻이 된다. 그럼 그 너머에 대한 정보는 굳이 가지고 있을 필요가 없는 값이니 값을 버리면 된다.

이 부분을 스택의 top()pop()을 잘 이용해서 결과 값을 배열에 저장한다면 완벽한 결과를 내줄 수 있을 것이다.



 

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
#include <iostream>
#include <stack>
using namespace std;
typedef struct _node
{
    int height;
    int idx;
}node;
 
int n, rec[500002];
node arr[500002];
 
int main(void)
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> arr[i].height;
        arr[i].idx = i;
        rec[i] = -1;
    }
 
    stack<node> s;
    int cnt = 1, bot = 0;
    for (int i = 1; i <= n; i++)
    {
        if (s.empty())
        {
            s.push(arr[i]);
        }
        else if (arr[i].height <= s.top().height)
        {
            rec[i] = s.top().idx;
            s.push(arr[i]);
        }
        else if (arr[i].height>s.top().height)
        {
            while (!s.empty() && !(arr[i].height <= s.top().height))
            {
                if (arr[i].height <= s.top().height)
                {
                    rec[i] = s.top().idx;
                    s.push(arr[i]);
                }
                else
                    s.pop();
            }
            if (s.empty())
                s.push(arr[i]);
            else
            {
                rec[i] = s.top().idx;
                s.push(arr[i]);
            }
        }
        if (rec[i] == -1)
            cout << "0" << " ";
        else
            cout << rec[i] << " ";
    }
}
cs

 

 

소스코드다.

별도의 연산이 조금 들어가 있어서 지저분하지만 스택을 사용했다는 것에 초점을 두자.

C++ stack을 이용하면 스택을 직접 구현하지 않고도 손쉽게 스택을 이용할 수 있어서 편리한데,

스택정도야 그냥 구현하기 쉬우니까 직접 구현하는 것도 나쁘지 않지만,

알고리즘 대회를 준비하고 있다면 기초적인 것들은 알아두는 게 좋지 않을까 싶다.

 

 

로그와 게시글과 관련된 문의나, 요구사항 등은 공지사항(http://twinparadox.tistory.com/notice/180)에 댓글을 남겨주시거나, 이메일(nww731@gmail.com)로 문의 바랍니다.

728x90