문제 : https://www.acmicpc.net/problem/18235


문제해석

 1 ~ N 까지 좌표들이 있고, 오리 두마리가 A 와 B 지점에서 시작해서 하루에 한 번 점프를 해가며 이동한다. 점프를 안하는 경우는 없고,  점프 크기는 1부터 시작해서 2배씩 늘어난다. 이때, 둘이 만날 수 있는지, 만난다면 몇 일이 지나고 만나는지를 구하는 프로그램을 작성하라.

문제핵심

 1. 점프 크기가 2배씩 늘어나므로 19일에 점프크기는 262,144(2^18)가 되고 N이 최대 500,000이므로 20일부터는 의미가 없어진다. 왜냐하면 20일 부터 점프 크기가 500,000보다 크므로 점프를 하면 어차피 범위를 벗어나게 된다. 따라서, 우리는 19일까지만 시뮬레이션을 진행해보면 된다. --> 19 * O(N) 으로 처리하자.

 2. 우리는 k 일에 A 오리와 B 오리가 갈 수 있는 모든 지점을 알고 있다면, (k + 1) 일에 A 오리와 B 오리가 갈 수 있는 모든 지점을 구할 수 있다. --> 모든 지점을 저장해가면서 진행해보자.

알고리즘

 문제핵심 1, 2번에 의해서 현재 A, B 오리가 도착한 지점을 통해 다음 A, B 오리가 도착한 지점을 저장해나가며 문제를 해결할 수 있다. 메모리를 조금이라도 아끼기위해 bool 배열과 flag 기법을 이용해서 저장해나갔다.

 day 0부터 시작해서 day가 짝수라면 visited[0] 에 현재 방문한 지점들이 있고, visited[1] 에 다음에 방문할 지점들을 check 해가며 문제를 해결했다.

 1) 현재 방문한 지점들 중에 겹치는 곳이 있는지. --> 있다면 오리가 만났다!

 2) 다음에 방문한 지점을 저장할 공간을 초기화한다.

 3) 현재 지점을 토대로 다음에 방문할 지점을 계산해 저장한다.

알고리즘회고

처음에는 2개의 deque를 이용해서 현재 A 오리가 갈 수 있는 모든 지점을 저장하고, B 오리가 갈 수 있는 모든 지점을 저장하고, deque의 앞에서부터 현재 지점들을 뽑아가며 jump 를 +, jump 를 - 해서 다음 지점들을 다시 deque의 뒤로 push 했다. 당연히 deque의 push, pop 이 굉장히 많이 일어났고, 현재 지점들에서 같은 지점이 있는지 없는지 체크를 위해 2개의 deque을 2중 for문으로 순회해야되서 시간초과를 맛보게 되었다. 따라서, 메모리를 조금 더 사용하고 deque을 사용하지 않는 방식으로 알고리즘을 갈아엎었다.

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
#include<iostream>
#include<qcueue>
#include<vector>
 
using namespace std;
int N, A, B, jump = 1, day = 0;
bool visitedA[2][500001= {};
bool visitedB[2][500001= {};
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
 
    // 19일 안에 만나야됨!
 
    cin >> N >> A >> B;
 
    visitedA[0][A] = 1;
    visitedB[0][B] = 1;
    do {
        // day 가 짝수라면 visited[0] 에 기존것이있음!
        // day 가 홀수라면 visited[1] 에 기존것이있음!
        int today = day % 2;
        int nextDay = (today + 1) % 2;
        // 같은게 있는지 찾아보자.
        bool flag = false;
        for (int i = 1; i <= N; i++) {
            if (visitedA[today][i] && visitedB[today][i]) {
                flag = true;
                break;
            }
        }
        if (flag) {
            cout << day << '\n';
            break;
        }
 
        // 초기화 진행
        for (int i = 1; i <= N; i++){
            visitedA[nextDay][i] = 0;
            visitedB[nextDay][i] = 0;
        }
        for (int i = 1; i <= N; i++) {
            int nextJump1 = i + jump, nextJump2 = i - jump;
            if (visitedA[today][i]) {
                if (1 <= nextJump1 && nextJump1 <= N) visitedA[nextDay][nextJump1] = 1;
                if (1 <= nextJump2 && nextJump2 <= N) visitedA[nextDay][nextJump2] = 1;
            }
            if (visitedB[today][i]) {
                if (1 <= nextJump1 && nextJump1 <= N) visitedB[nextDay][nextJump1] = 1;
                if (1 <= nextJump2 && nextJump2 <= N) visitedB[nextDay][nextJump2] = 1;
            }
        }
        jump *= 2;
        day++;
    } while (jump <= 500000);
    if (jump > 500000cout << -1;
    return 0;
}
cs

 

'Problem Solving > BOJ' 카테고리의 다른 글

[BOJ] 3109 : PLINOVOD  (0) 2020.07.01
[BOJ] 15681 : 트리와 쿼리  (0) 2020.07.01
[BOJ]15591 : MooTube(Silver)  (0) 2020.06.22
[BOJ] 10021 : Watering the Fields  (0) 2020.06.22
[BOJ] 2352 : 반도체 설계  (0) 2020.06.15

+ Recent posts