https://www.acmicpc.net/problem/1655

 

1655번: 가운데를 말해요

첫째 줄에는 수빈이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 수빈이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.

www.acmicpc.net

값이 계속 들어올 때마다 중간값을 출력해주어야 하기 때문에 매번 정렬을 해서 가운데 값을 출력해주면 시간 초과가 발생한다. 따라서 이 문제는 최대 힙(Max heap) 최소 힙(Min heap) (우선순위 큐)을 사용하여 풀 수 있다.

 

 

1. 최소 힙의 값들은 모두 최대 힙보다 크도록하고

2. 최대 힙의 크기가 최소 힙의 크기보다 1 크거나 같도록 유지하며 값을 넣는다.

3. 값을 넣어준 후 최대 힙과 최소 힙의 top 값을 비교해서 최소 힙의 top보다 최대 힙의 top이 더 크다면 값을 교환해준다.

그러면 최대 힙의 top값이 중간값이 된다.

 

 

문제의 예제 중 마지막 값인 5를 6으로 수정해서 예를 들어봤다.

1 5 2 10 -99 7 6

위와 같은 값들을 순차적으로 입력받는다고 하면

 

처음에 들어온 1은 max heap에 들어간다. 중간 값은 1

max heap : 1

min heap : 

 

 

다음에 5가 들어오면 max heap의 크기가 더 크므로 min heap에 값이 들어간다.

max heap : 1

min heap : 5

이때, max heap의 top보다 min heap의 top이 크므로 값의 변경은 일어나지 않고, 중간값은 max heap의 top인 1이다.

 

 

그다음에 2가 들어오면 크기가 같으므로 max heap에 들어가고 2는 5보다 작으므로 값의 변경은 일어나지 않는다.

max heap의 top인 2가 중간 값이다.

max heap : 1, 2

min heap : 5

 

 

다음으로 10이 들어오면 min heap의 크기가 더 작으므로 min heap에 들어가고 중간 값은 max heap의 top값인 2이다.

max heap : 1, 2

min heap : 5, 10

 

 

-99는 두 heap의 사이즈가 같으므로 max heap에 들어가고 중간 값은 2이다.

max heap : -99, 1, 2

min heap : 5, 10

 

 

7은 min heap으로 들어간다. 중간 값은 그대로 2이다.

max heap : -99, 1, 2

min heap : 5, 7, 10

 

 

마지막으로 6은 두 heap의 사이즈가 같으므로 max heap에 들어간다.

max heap : -99, 1, 2, 6

min heap : 5, 7, 10

 

이때, max heap의 top인 6이 min heap의 top인 5보다 크므로 두 값을 교환해주어야 한다.

max heap : -99, 1, 2, 5

min heap : 6, 7, 10

교환해주고 나면 max heap의 top인 5가 중간값이 된다.

 

 

 

c++에서 우선순위 큐는 기본적으로 최대 힙이기 때문에 최대 힙은 그냥 우선순위 큐를 하나 만들어주면 되고

최소 힙은 functionl을 include 해준후

 priority_queue<intvector<int>, greater<int>> minheap;

이런 식으로 greater를 이용해서 만들어주면 된다.

 

처음에는 minheap에 값이 없으므로 top값을 가져올 수 없으므로 maxheap에만 값을 추가하고 다시 다른 값을 입력받도록 처리해주어야 한다. 아니면 top값을 비교할 때 minheap이 비어있는지를 검사해줘도 된다.

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
#include<iostream>
#include <functional>
#include <queue>
using namespace std;
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    priority_queue<int> maxheap;
    priority_queue<intvector<int>, greater<int>> minheap;
 
    int n;
    cin >> n;
 
    int x;
    for (int i = 0; i < n; i++) {
        cin >> x;
 
        //처음에 값이 없는 경우
        if (maxheap.size() == 0) {
            maxheap.push(x);
        }
        else {
 
            //최대 힙의 크기가 더 크다면 최소 힙에 값을 넣는다.
            if (maxheap.size() > minheap.size()) {
                minheap.push(x);
            }
            else {
                //크기가 같다면 최대 힙에 넣는다.
                maxheap.push(x);
            }
 
            //최대 힙의 top의 값(최댓값)이 최소 힙의 최솟값보다 크다면 값을 교환한다.
            if (maxheap.top() > minheap.top()) {
                int maxtop = maxheap.top();
                int mintop = minheap.top();
                maxheap.pop();
                minheap.pop();
                maxheap.push(mintop);
                minheap.push(maxtop);
            }
 
        }
        
 
        //중간값을 출력
        cout << maxheap.top() << '\n';
    }
 
    
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 11729. 하노이 탑 이동 순서  (0) 2019.08.31
[BOJ] 별 찍기 - 10  (0) 2019.08.31
[BOJ] 17143. 낚시왕  (0) 2019.08.18
[BOJ] 17406. 배열 돌리기 4  (0) 2019.08.13
[BOJ] 2468. 안전 영역  (0) 2019.08.13

https://www.acmicpc.net/problem/17143

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다. 낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하

www.acmicpc.net

(수정)

이전의 풀이가 재채점 후에 시간 초과로 바뀌어서 다시 풀었다...

속력 s만큼 이동하면 안되고 결국 똑같은 범위 안에서 왔다 갔다 하는 것이므로 % 연산을 사용하여 이동을 단축시킬 수 있다. 즉 상하로 움직이는 경우에는 (r-1) * 2 , 좌우로 움직이는 경우에는 (c-1) * 2  만큼 움직일 때 원래 자리로 돌아온다.

 

//상하로 움직이는 경우

  if (d <= 2) {

        s = s % ((R-1* 2);

  }

  else { //좌우로 움직이는 경우

        s = s % ((C-1* 2);

  }

 

s만큼 이동하기 전에 이렇게 추가해줘서 pass하였다.

 

 

 

 

시뮬레이션 문제인데 상어들이 같은 곳에 있을 때의 처리를 해주는 게 어려웠다.

swea의 미생물 격리(?) 문제랑 살짝 비슷한 것 같다(미생물 격리가 더 어려움)

 

문제에서 주어지는 상어의 좌표, 속력, 방향, 크기의 정보와 추가적으로 살아있는지 여부를 확인할 bool변수

구조체로 저장하여 관리하였다.

또한, 배열을 만들어서 상어의 위치에 상어의 인덱스를 저장하였다.(상어의 인덱스는 입력받은 순서다)

예를 들어 두 번째 상어의 좌표가 (1,3)이었다면 map [1][3] = 2

이런 식으로 저장하고 이동하거나 죽으면 다시 0으로 바꿔줬다.

 

이 배열을 활용하면 낚시왕이 상어를 잡을 때 낚시왕이 서있는 열만 배열에서 쭉 확인해주면 되므로

쉽게 구현할 수 있다.

 

두 마리 이상의 상어들이 같은 곳에 위치할 때에도 이 배열을 확인하였다.

이동할 좌표에 대해 다음과 같이 나눠서 처리해주었다.

r, c로 이동한다고 가정했을 때,

  • map[r][c] = 0 인 경우 ( 다른 상어가 없다)
    • 바로 map[r][c]에 현재 상어의 인덱스를 저장하면 된다.
  • map[r][c] > i 인 경우 ( 이전 인덱스의 상어가 와 있는 경우 ) // 인덱스 순서대로 진행하지면 동시에 일어나는 일이다!!
    • 현재 이동(같은 시간)에서 와 있는 상어이므로 크기를 비교 후 더 큰 상어가 해당 위치에 남아있게 된다.
  • map[r][c] < i 인 경우 ( 다음 인덱스의 상어의 번호가 있는 경우) 이전 이동(이전 시간)에서의 상어의 위치이다.
    • 다음 인덱스의 상어는 어차피 좀 이따 이동시켜줄 것이므로 그냥 첫 번째 경우처럼 바로 저장해주면 된다.

 

좀 더 자세한 설명은 코드의 주석 참고!

 
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int R, C, M;
int dx[] = { 0,-1,1,0,0 };
int dy[] = { 0,0,0,1,-1 };
 
int map[101][101];
 
 
struct Shark {
    int r;
    int c;
    int s;
    int d;
    int z;
 
    //살아있는지 여부
    bool isAlive;
};
 
vector<Shark> vt;
 
int getShark(int c) {
    int getsize = 0;
 
    //낚시왕이 서있는 열의 행들만 검사한다.
    for (int i = 1; i <= R; i++) {
 
        //상어가 있으면
        if (map[i][c] != 0) {
 
            //크기를 받아오고
            getsize = vt[map[i][c]].z;
 
            //잡았으므로 죽인다.
            vt[map[i][c]].isAlive = false;
 
            //해당위치에서 지워준다.
            map[i][c] = 0;
 
            //가장 가까운 한마리만 잡음로 break
            break;
        }
    }
 
    //크기를 리턴
    return getsize;
}
 
void sharkMove() {
 
    int r, c, s, d, z;
    for (int i = 1; i <= M; i++) {
        //죽은 상어는 skip
        if (vt[i].isAlive == falsecontinue;
 
        r = vt[i].r;
        c = vt[i].c;
        s = vt[i].s;
        d = vt[i].d;
        z = vt[i].z;
 
        //다른 곳으로 이동할 것이므로 원래 있던 자리를 0으로 넣어준다.
        //이전 index의 상어가 현재 상어의 자리에 와 있지 않은 경우에만 0으로 초기화
        if (map[r][c] == i) {
            map[r][c] = 0;
        }
 
        
        //s를 줄여준다.
        if (d <= 2) {
            s = s % ((R-1* 2);
        }
        else {
            s = s % ((C-1* 2);
        }
        
 
        //스피드(s)만큼 d방향으로 이동
        for (int j = 0; j < s; j++) {
            r += dx[d];
            c += dy[d];
 
            //범위를 넘어가는 경우
            if (r < 1 || c < 1 || r > R || c > C) {
                if (d == 1 || d == 3) {
                    d += 1;
                }
                else {
                    d -= 1;
                }
 
                //범위 안으로 하나 들어오고
                r += dx[d];
                c += dy[d];
 
                //j는 다시 빼준다.(한 번 잘못 움직인 것 이므로)
                j--;
            }
 
        }
 
        //변경된 좌표와 방향을 상어 정보에 새로 저장
        vt[i].r = r;
        vt[i].c = c;
        vt[i].d = d;
 
 
        //이동한 곳에 다른 상어가 없다면 바로 저장
        if (map[r][c] == 0) {
            map[r][c] = i;
        }
        else if (map[r][c] < i) {
            // 이전 인덱스의 상어가 있는 경우에는 크기가 더 큰 상어가 더 작은 상어를 잡아먹는다.
 
            int tmp = vt[map[r][c]].z;
            if (z > tmp) {
                //현재 인덱스의 상어가 더 큰 경우 원래 있던 상어를 잡아먹는다.
                vt[map[r][c]].isAlive = false;
                map[r][c] = i;
            }
            else {
                //현재 인덱스의 상어가 더 작은 경우 잡아먹힌다.
                vt[i].isAlive = false;
            }
        }
        else {
            //현재 인덱스보다 뒷순서의 상어라면 어차피 이동할 것이므로 그냥 덮어쓴다.
            map[r][c] = i;
        }
 
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> R >> C >> M;
 
 
    //상어의 수가 0인 경우는 바로 0을 출력하고 종료
    if (M == 0) {
        cout << 0 << '\n';
        return 0;
    }
 
    int r, c, s, d, z;
 
    //index를 1부터 시작해주기 위해서 0번째에 아무거나 넣어놓는다.
    vt.push_back({ 0,0,0,0,0 });
    for (int i = 1; i <= M; i++) {
        cin >> r >> c >> s >> d >> z;
 
        //상어 정보를 벡터에 넣는다.
        vt.push_back({ r,c,s,d,z,true });
 
        //배열에 위치한 상어의 index를 저장
        map[r][c] = i;
    }
 
    int ans = 0;
    //C만큼 실행
    for (int i = 1; i <= C; i++) {
        ans += getShark(i);
        sharkMove();
    }
 
    cout << ans << "\n";
 
    return 0;
}
Colored by Color Scripter
 

 

'BOJ' 카테고리의 다른 글

[BOJ] 별 찍기 - 10  (0) 2019.08.31
[BOJ] 1655. 가운데를 말해요  (2) 2019.08.30
[BOJ] 17406. 배열 돌리기 4  (0) 2019.08.13
[BOJ] 2468. 안전 영역  (0) 2019.08.13
[BOJ] 2573. 빙산  (0) 2019.08.13

https://www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의 값은 4이다. 1 2 3 2 1 1 4 5 6 배열은 회전 연산을 수행할 수 있다. 회전 연산은 세 정수 (r, c, s)로 이루어져 있고, 가장 왼쪽 윗 칸이 (r-s, c-s), 가장 오른쪽 아랫 칸이 (r+s, c+s)인 정사각형을 시계

www.acmicpc.net

회전 연산을 사용하는 모든 경우를 구해주고 배열을 회전시켜줘야 하는 문제이다.

즉, 완전 탐색 + 시뮬레이션이다.

 

 

회전 정보는 구조체로 만들어서 벡터에 저장하여 관리하였다.

그리고 문제에서 (1,1)부터 시작하므로 r과 c 좌표는 각각 1씩 빼주었다.

정답의 최댓값은 행의 최대길이 50 * 칸의 최댓값 100으로 5000정도이지만 그냥 안전하게 10000 정도를 초기값으로 넣어놨다.

 

 

 회전 연산은 모두 한 번씩 사용해야 하며, 순서는 임의로 정해도 된다.

라는 문제 조건에 따라 사용할 회전 연산 순서를 모두 정해준다.

순서를 정할 때마다 새로운 배열을 만들어서 배열을 회전시켜준 상태로 넘겨준다.

그리고 k개 만큼 순서를 모두 정했다면 그때의 배열의 값(행의 합 중 최솟값)을 구해준다.

 

 

회전을 시킬 때는 밑의 그림에서 파란 네모로 묶인 애들을 각각 for문을 사용해서 옮겨줬다.

즉 for문을 4번 사용하여 회전시켰다.

(r-s, c-s)를 시작점으로 배열을 회전시켜줄 건데 이 부분의 값은 따로 빼놓는다.

그리고 첫번째 for문에서 밑의 칸들을 하나하나 올려준다.

그리고 다시 두 번째 for문에서 오른쪽 칸들을 옆으로 하나하나 옮겨준다.

옮겨주다가 맨 윗줄을 이동시켜줄 때는 마지막 칸을 옮기면 안 되고 처음에 빼놨던 (r-s, c-s) 값을 넣어줘야 한다.

 

 

s가 2인 경우에는 2인 경우와 1인 경우 모두 구해줘야 하기 때문에 s 값을 줄여가면서 배열을 모두 돌려주면 된다.

2부터 시작해서 r-2, c-2를 시작점으로 배열을 회전시키고 난 후에 s 값을 1 감소시켜서

다시 r-1, c-1을 시작점으로 다시 배열을 회전시켜주면 된다.

마찬가지로 s가 더 큰 값일 경우에도 s 수만큼 배열을 회전시키면 된다.

 

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
 
int ans;
int n, m, k;
bool check[6];
 
struct Info {
    int x;
    int y;
    int size;
    Info(int x, int y, int size) : x(x), y(y), size(size) {}
};
 
vector<Info> vt;
 
void move(int index, int map[50][50]) {
    //index번째 회전 연산의 정보를 가져온다.
    int x = vt[index].x;
    int y = vt[index].y;
    int s = vt[index].size;
 
    while (s > 0) {
 
        int tmp = map[x - s][y - s];
 
        //첫번째 열 이동
        for (int i = x - s; i < x + s; i++) {
            map[i][y - s] = map[i + 1][y - s];
        }
 
        //마지막 행 이동
        for (int j = y - s; j < y + s; j++) {
            map[x + s][j] = map[x + s][j + 1];
        }
 
        //마지막 열 이동
        for (int i = x + s; i > x - s; i--) {
            map[i][y + s] = map[i - 1][y + s];
        }
 
        //첫번째 행 이동
        for (int j = y + s; j > y - s + 1; j--) {
            map[x - s][j] = map[x - s][j - 1];
        }
 
        //마지막 칸
        map[x - s][y - s + 1= tmp;
        s--;
    }
 
}
 
 
void mapcpy(int map[50][50], int newmap[50][50]) {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            newmap[i][j] = map[i][j];
        }
    }
}
 
 
//각 행의 합 중 최솟값을 구한다.
void calc(int map[50][50]) {
    for (int i = 0; i < n; i++) {
        int sum = 0;
        for (int j = 0; j < m; j++) {
            sum += map[i][j];
        }
        if (ans > sum) ans = sum;
    }
}
 
 
void solve(int index, int map[50][50]) {
    if (index == k) {
        //회전 연산을 모두 사용하였으면 계산
        calc(map);
        return;
    }
 
 
    for (int i = 0; i < k; i++) {
        //i번을 이미 사용
        if (check[i]) continue;
 
        int newmap[50][50];
        mapcpy(map, newmap);
 
        //사용 표시후에 배열을 회전시킨다.
        check[i] = true;
        move(i, newmap);
 
        //배열을 회전 시킨 상태에서 다음 회전을 사용하는 경우를 구한다.
        solve(index + 1, newmap);
 
        //다른 회전을 사용하는 경우를 위해 다시 사용 표시 없앤다.
        check[i] = false;
 
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n >> m >> k;
    ans = 10000;
    int map[50][50];
    for (int i = 0; i < n; i++) {
        int sum = 0;
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }
 
    int r, c, s;
    for (int i = 0; i < k; i++) {
        cin >> r >> c >> s;
        r--;
        c--;
        vt.push_back(Info(r, c, s));
    }
 
 
    solve(0, map);
 
    cout << ans << '\n';
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1655. 가운데를 말해요  (2) 2019.08.30
[BOJ] 17143. 낚시왕  (0) 2019.08.18
[BOJ] 2468. 안전 영역  (0) 2019.08.13
[BOJ] 2573. 빙산  (0) 2019.08.13
[BOJ] 2234. 성곽  (0) 2019.08.13

https://www.acmicpc.net/problem/2468

 

2468번: 안전 영역

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는 안전한 영역이 최대로 몇 개가 만들어 지는 지를 조사하려고 한다. 이때, 문제를 간단하게 하기 위하여, 장마철에 내리는 비의 양에 따라 일정한 높이 이하의 모든 지점은 물에 잠긴다고 가정한다. 어떤 지역의 높이 정보는 행과 열의 크기가 각각 N인 2차원 배열 형태로 주어

www.acmicpc.net

안전 영역을 구해줄 것이므로 물에 잠기지 않는 부분에 대해서 BFS를 해준다.

그리고 BFS를 한 횟수가 안전영역의 수가 된다.

 

 

지역의 높이 범위가 1부터 100인데 시간을 줄이기 위해서 지역의 정보를 처음에 입력을 받을 때 지역 높이의 최댓값을 구해놓는다.

그리고 1부터 높이의 최댓값 -1 까지만큼 비가 오는 경우를 모두 구해주면 된다.

높이의 최댓값 이상으로 비가 오는 경우는 안전 영역이 0이 되기 때문이다.

그리고 각 경우에서의 안전 영역을 정답(최댓값)과 비교해서 저장한다.

 

주의할 점은 

아무 지역도 물에 잠기지 않을 수도 있다.

라고 문제 밑부분 노트에 쓰여있는데 이 경우는 안전 영역이 1이므로 정답의 초기값은 0이 아닌 1로 해놓아야 한다.

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
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
 
int n;
int maxh;
int ans;
int map[100][100];
bool check[100][100];
 
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
 
void bfs(int x, int y, int h) {
 
    queue<pair<intint>> q;
    q.push(make_pair(x, y));
    check[x][y] = true;
 
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
            if (check[nx][ny]) continue;
            if (map[nx][ny] <= h) continue;
 
            q.push(make_pair(nx, ny));
            check[nx][ny] = true;
        }
    }
 
}
 
void solve() {
 
 
    for (int h = 1; h < maxh; h++) {
        memset(check, falsesizeof(check));
        int safearea = 0;
 
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (check[i][j]) continue;
                //높이가 더 낮은 곳은 물에 잠기므로 넘어간다
                if (map[i][j] <= h) continue;
 
                bfs(i, j, h);
                safearea++;
            }
        }
 
        if (ans < safearea) ans = safearea;
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            if (maxh < map[i][j]) maxh = map[i][j];
        }
    }
 
 
    ans = 1;
    
    solve();
    cout << ans << '\n';
 
    return 0;
}
Colored by Color Scripter
 

 

'BOJ' 카테고리의 다른 글

[BOJ] 17143. 낚시왕  (0) 2019.08.18
[BOJ] 17406. 배열 돌리기 4  (0) 2019.08.13
[BOJ] 2573. 빙산  (0) 2019.08.13
[BOJ] 2234. 성곽  (0) 2019.08.13
[BOJ] 11559. Puyo Puyo  (0) 2019.08.08

https://www.acmicpc.net/problem/2573

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0 이상 10 이하이다. 배열에서 빙산이 차지하는 칸의 개수, 즉, 1 이상의 정수가 들어가는 칸의 개수는 10,000 개 이하이다. 배열의 첫 번째 행과 열, 마지

www.acmicpc.net

BFS를 이용해서 푸는 문제이다.

 

인접한 칸이 바다인 경우에는 그 개수를 세주어서 빙산의 높이에서 빼주면 된다.

바다가 아닌 빙산인 경우에는 큐에 넣어주고 해당 빙산에 대해서도 탐색을 이어가면 된다.

 

 

BFS는 연결된 모든 칸을 방문하기 때문에 연결되지 않은 칸에 방문하기 위해서는 BFS를 새로 시작하여야 한다.

즉, bfs횟수가 1회일 때는 아직 모두 연결되어 있는 한 덩어리라는 뜻이므로 계속 시간을 늘려가며 bfs를 진행하고

BFS 횟수가 1번이 넘을 때는 빙산이 두 덩어리 이상이 됐음을 의미하므로 그때 시간을 출력해주고 탐색을 종료한다.

 

 

만약 다 녹았는데 빙산이 분리되지 않은 경우를 처리하기 위해서는 flag 변수를 둬서 bfs탐색이 한 번도 일어나지 않은 경우에 0을 출력해주고 종료하도록 해줬다.

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
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
 
int n, m;
int map[300][300];
bool check[300][300];
 
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
 
void bfs(int x, int y) {
    queue<pair<intint>> q;
    q.push(make_pair(x, y));
    check[x][y] = true;
 
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        int cnt = 0;
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            
            if (check[nx][ny]) continue;
 
            //인접한 칸이 바다인 경우 cnt증가
            if (map[nx][ny] == 0) {
                cnt++;
            }
            else {
                //빙산인 경우에는 큐에 넣어주고 계속 탐색
                q.push(make_pair(nx, ny));
                check[nx][ny] = true;
            }
            
        }
 
 
        //인접해 있는 바다의 수만큼 높이 줄어든다.
        map[x][y] -= cnt;
        //0보다 작아지지는 않는다.
        if (map[x][y] < 0) map[x][y] = 0;
 
    }
 
}
 
void solve() {
 
    int time = 0;
    while (true) {
        int cnt = 0;
        bool flag = false;
        for (int i = 1; i < n - 1; i++) {
            for (int j = 1; j < m - 1; j++) {
                //바다인 경우 continue
                if (map[i][j] == 0continue;
                //이미 방문한 경우
                if (check[i][j]) continue;
 
                //빙산이 아직 있다.
                flag = true;
                bfs(i, j);
 
                //빙산의 덩어리 수
                cnt++;
            }
        }
 
        //전부 다 녹을 때까지 두덩어리 이상으로 분리되지 않는 경우
        if (!flag) {
            cout << 0 << '\n';
            return;
        }
 
 
        //두 덩어리 이상이 되었을 경우 시간을 출력하고 return(종료)
        if (cnt > 1) {
            cout << time << "\n";
            return;
        }
 
 
        //시간 증가
        time++;
 
        memset(check, falsesizeof(check));
    }
 
    
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }
 
    solve();
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 17406. 배열 돌리기 4  (0) 2019.08.13
[BOJ] 2468. 안전 영역  (0) 2019.08.13
[BOJ] 2234. 성곽  (0) 2019.08.13
[BOJ] 11559. Puyo Puyo  (0) 2019.08.08
[BOJ] 3190. 뱀  (0) 2019.08.06

https://www.acmicpc.net/problem/2234

 

2234번: 성곽

문제 대략 위의 그림과 같이 생긴 성곽이 있다. 굵은 선은 벽을 나타내고, 점선은 벽이 없어서 지나다닐 수 있는 통로를 나타낸다. 이러한 형태의 성의 지도를 입력받아서 다음을 계산하는 프로그램을 작성하시오. 이 성에 있는 방의 개수 가장 넓은 방의 넓이 하나의 벽을 제거하여 얻을 수 있는 가장 넓은 방의 크기 위의 예에서는 방은 5개고, 가장 큰 방은 9개의 칸으로 이루어져 있으며, 위의 그림에서 화살표가 가리키는 벽을 제거하면 16인 크기의 방을 얻을

www.acmicpc.net

  1. 이 성에 있는 방의 개수
  2. 가장 넓은 방의 넓이
  3. 하나의 벽을 제거하여 얻을 수 있는 가장 넓은 방의 크기

를 구하는 문제이다. 이 문제는 bfs와 비트 마스크를 사용해서 풀었다.

 

 

먼저 1번과 2번문제에 대한 답을 먼저 구하였다.

방문하지 않은 모든 칸에 bfs를 사용하여 방문하고 bfs가 시작될 때마다(새로운 방이므로) 방 개수를 늘려준다.

그리고 bfs탐색을 할때마다 방문하는 칸의 개수를 세줘서 방의 넓이를 구하여 방의 넓이 중 최댓값을 구할 수 있다.

 

이 문제에서 bfs를 할 때 중요한 부분은 벽인지 아닌지 알아내야 한다.

 

 

벽에 대한 정보는 한 정수로 주어지는데, 서쪽에 벽이 있을 때는 1을, 북쪽에 벽이 있을 때는 2를, 동쪽에 벽이 있을 때는 4를, 남쪽에 벽이 있을 때는 8을 더한 값이 주어진다. 참고로 이진수의 각 비트를 생각하면 쉽다. 따라서 이 값은 0부터 15까지의 범위 안에 있다.

라고 문제 입력에서 주어지는데 이 부분이 힌트인 것 같다. 그림으로 나타내면 아래와 같다.

 

 

 

 

문제에서 주어진 예시 그림(맨 위 그림)의 왼쪽 끝칸(0,0)을 예시로 들어보면 아래 그림과 같다. 서쪽, 북쪽, 남쪽에 벽이 있기 때문에

1+2+8 = 11로 11이 문제 입력에서 주어진다. 11은 다시 이진수로 1011로 나타낼 수 있으므로 이를 이용해서 비트 마스크로 검사를 한다.

int dx[] = { 0,-1,0,1 };

int dy[] = { -1,0,1,0 };

먼저 방향 배열을 서, 북, 동, 남 순서로 해놓아야 한다. 그래야 1 << 0을 했을 때의 값이 1이므로 서쪽을 표현할 수 있고 1<<1 은 2로 북쪽을 표현할 수 있다.

그리고 검사할 칸과 & (1<<k)를 해서 해당 위치에 1을 가지고 있는지 검사한다. (k는 0부터 3으로 네 방향의 index)

1을 가지고 있는 경우(위의 연산 결과가 0이 아닌 경우)에는 벽이므로 해당 방향으로는 이동하지 않는다.

 

 

그리고 나중에 3번 문제를 해결하기 위해서플러드 필 알고리즘(연결 요소에 번호를 매김)을 사용한다. bfs를 할 때 현재 연결된 칸들에 방 번호를 매겨주고 각 방의 넓이 또한 cnt 배열에 저장해놓는다.

 

 

3번 문제를 해결하기 위해서는 다음과 같은 생각을 했다.

인접해있는 방과 현재 방의 넓이를 합쳤을 때의 최댓값이 하나의 벽을 제거했을 때의 결과와 마찬가지다.

아래 그림을 봤을 때 1번 방은 2번 방과 3번 방과 인접해있는데 3번 방과 인접해있는 벽 중 하나를 제거했을 때 최댓값을 얻을 수 있다.

 

 

코드로 구현하자면 다시 새로운 bfs를 이용한다. 이때 bfs에서는 아까 플러드 필 알고리즘을 사용하여 방 번호를 매긴 배열을 이용한다.

이동했을 때 같은 방인 경우에는 계속 큐에 넣고 방문 체크를 해주며 탐색을 이어가고 같은 방이 아닌 경우에는 현재 방의 칸수와 옆의 방의 칸수를 합친 값(위에서 저장한 cnt배열을 이용)을 저장하고 이 합쳐진 값들 중 최댓값이 정답이 된다.

 

1번 방에 대해 인접한 방에 대해서 모두 탐색을 해봤다면 다음 2번 방을 검사할 때는 다시 1번 방과 비교할 필요는 없다.

그러므로 bfs로 방문한 칸은 모두 다 체크해주면 된다.

 

 

역시 코드를 보는 게 가장 이해하기 쉬울 것 같다ㅎㅎ

순서는 main -> solve -> bfs 다음에 removeWall -> bfs2로 진행된다.

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
 
int m, n;
int map[50][50];
int visit[50][50];
bool check[50][50];
int cnt[2500];
 
 
int dx[] = { 0,-1,0,1 };
int dy[] = { -1,0,1,0 };
 
int bfs2(int x, int y) {
    queue<pair<intint>> q;
    q.push(make_pair(x, y));
    check[x][y] = true;
 
    int sum = 0;
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
            if (check[nx][ny]) continue;
 
 
            //같은 방이면 큐에 넣고
            if (visit[nx][ny] == visit[x][y]) {
                q.push(make_pair(nx, ny));
                check[nx][ny] = true;
            }
            else { //다른 방이면 그 방과 합쳐졌을 때의 넓이를 저장
                int tmp = cnt[visit[x][y]] + cnt[visit[nx][ny]];
                if (sum < tmp) sum = tmp;
            }
 
        }
    }
 
    return sum;
 
}
 
void removeWall() {
    queue<pair<intint>> q;
 
    int sum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (check[i][j]) continue;
            int tmp = bfs2(i, j);
            if (sum < tmp) sum = tmp;
        }
    }
    
    cout << sum << '\n';
}
 
int bfs(int x, int y, int num) {
    int cnt = 1;
    queue<pair<intint>> q;
    q.push(make_pair(x, y));
    visit[x][y] = num;
 
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        for (int k = 0; k < 4; k++) {
            //해당 방향이 벽인 경우
            if (map[x][y] & (1 << k)) continue;
 
            int nx = x + dx[k];
            int ny = y + dy[k];
 
            if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
            if (visit[nx][ny]) continue;
 
            q.push(make_pair(nx, ny));
 
            //방 번호를 기록
            visit[nx][ny] = num;
            cnt++;
        }
 
    }
 
 
    //연결된 칸의 개수를 리턴(방의 넓이)
    return cnt;
}
 
void solve() {
 
    int maxcnt = 0;
    int roomcnt = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (visit[i][j]) continue;
 
            //bfs출발할 때마다 방의 개수 늘어난다
            int tmp = bfs(i, j, ++roomcnt);
 
            //방 별로 넓이를 저장해놓는다.
            cnt[roomcnt] = tmp;
 
            //가장 넓은 방의 넓이
            if (maxcnt < tmp) maxcnt = tmp;
        }
    }
 
    //1번 답 출력
    cout << roomcnt << "\n";
 
    //2번 답 출력
    cout << maxcnt << "\n";
 
 
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> m >> n;
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }
 
    //1번과 2번 답을 구한다
    solve();
 
    //3번 답을 구한다
    removeWall();
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2468. 안전 영역  (0) 2019.08.13
[BOJ] 2573. 빙산  (0) 2019.08.13
[BOJ] 11559. Puyo Puyo  (0) 2019.08.08
[BOJ] 3190. 뱀  (0) 2019.08.06
[BOJ] 15683. 감시  (0) 2019.08.05

https://www.acmicpc.net/problem/11559

 

11559번: Puyo Puyo

현재 주어진 상황에서 몇연쇄가 되는지 출력하라. (하나도 터지지 않는다면 0을 출력하면 된다.)

www.acmicpc.net

시뮬레이션 카테고리에 넣었지만 BFS도 이용하는 문제이다.

BFS는 상하좌우로 연결되어 있는 같은 색의 뿌요를 찾기 위해 사용한다.

 

 

먼저 연쇄가 몇 번 일어났는지를 알아내야 하는 문제이기 때문에 연쇄가 일어나지 않을 때까지 터뜨리기를 반복해야한다.

 

 

각 반복에서는 뿌요가 있는 모든 칸에 대해서 BFS탐색을 통해 상하좌우로 연결된 같은 색의 뿌요가 네 개 이상 있는지 체크해준다. 있다면 해당 칸의 뿌요들을 터뜨려주고(.으로 만들어 준다) 연쇄가 발생했다는 뜻으로 true를 리턴한다.

문제 조건에 따라 여러 그룹의 뿌요가 터졌더라도 연쇄는 한 번 일어난 걸로 간주한다.

예를 들어, 전체 칸을 탐색할 때 R이 4개 이상 모여있었고 다른 곳에서 G가 4개이상 모여있어서 두 그룹이 터졌다고 해도 같은 턴에 터지는 애들은 한번 일어난 걸로 count 해준다.

 

 

모든 뿌요에 대해서 탐색을 해줬는데 flag가 false라면 (한 번도 연쇄가 발생하지 않았다면) 반복문을 break 해주고 정답을 출력해주면 된다.

 

flag가 true라면(연쇄가 적어도 한 번 이상 발생했다면) 떠있는 뿌요들을 바닥에 내려주고 연쇄가 일어난 횟수(정답)를 증가시킨다.

 

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
 
char map[12][6];
int check[12][6];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
int ans;
 
void move() {
    for (int j = 0; j < 6; j++) {
        for (int i = 11; i >= 0; i--) {
            if (map[i][j] != '.'continue;
 
            //빈 칸(.)을 찾았으므로 위에 떠있는 애를 찾는다.
            bool flag = false;
            for (int k = i - 1; k >= 0; k--) {
                
                //떠있는애 발견
                if (map[k][j] != '.') {
                    //내려준다.
                    map[i][j] = map[k][j];
                    map[k][j] = '.';
                    flag = true;
                    break;
                }
            }
 
            //위에 떠있는게 없으면 다음 열을 검사한다.
            if (!flag) {
                break;
            }
        }
    }
}
 
bool bfs(int x, int y) {
    queue<pair<intint>> q;
    memset(check, falsesizeof(check));
    
    q.push(make_pair(x, y));
    check[x][y] = true;
    int cnt = 1;
 
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            
            //범위 체크
            if (nx < 0 || ny < 0 || nx >= 12 || ny >= 6continue;
            //방문 체크
            if (check[nx][ny]) continue;
            //같은 색인지 체크
            if (map[nx][ny] != map[x][y]) continue;
 
            q.push(make_pair(nx, ny));
            check[nx][ny] = true;
            cnt++;
        }
    }
 
 
    //같은 색의 뿌요가 4개이상 존재하면 모두 터진다.
    if (cnt >= 4) {
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 6; j++) {
                if (check[i][j]) map[i][j] = '.';
            }
        }
        
 
        return true;
    }
    else return false;
}
 
void solve() {
    
    
    while (true) {
 
        bool flag = false;
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 6; j++) {
                if (map[i][j] == '.'continue//빈칸
 
                //같은 색의 뿌요들이 4개이상 모여있어서 터지는지 검사
                if (bfs(i, j)) {
                    flag = true;
                }
 
            }
        }
 
        //더 이상 터질게 없다.
        if (!flag) break;
        else {
            //터졌으면 중력에 의해 뿌요들이 아래로 떨어진다.
            move();
 
            ans++;
        }
 
    }
 
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    string s;
    for (int i = 0; i < 12; i++) {
        cin >> s;
        for (int j = 0; j < 6; j++) {
            map[i][j] = s[j];
        }
    }
 
    solve();
 
 
    cout << ans << '\n';
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2573. 빙산  (0) 2019.08.13
[BOJ] 2234. 성곽  (0) 2019.08.13
[BOJ] 3190. 뱀  (0) 2019.08.06
[BOJ] 15683. 감시  (0) 2019.08.05
[BOJ] 14500. 테트로미노  (0) 2019.08.04

https://www.acmicpc.net/problem/3190

 

3190번: 뱀

문제  'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임은 NxN 정사각 보드위에서 진행되고, 몇몇 칸에는 사과가 놓여져 있다. 보드의 상하좌우 끝에 벽이 있다. 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 뱀은 처음에 오른쪽을 향한다. 뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따

www.acmicpc.net

이 문제에서 어려운 점은 뱀이 자기 몸에 부딪혀서 게임이 끝날때를 처리해주는 부분인 것 같다.

이 부분은 몸길이칸에 머리가 있었던 시간을 저장한 배열을 이용하면 쉽게 구할 수 있다.

 

(현재 시간 - 몸길이)가 이동할 칸에 이전에 머리가 있었던 시간보다 작으면 몸에 부딪힌 것 이다

 

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
#include <iostream>
#include <vector>
using namespace std;
 
int dx[] = { 0,1,0,-1 };
int dy[] = { 1,0,-1,0 };
 
 
int n, k;
 
//사과의 좌표를 저장
bool apple[100][100];
 
//머리가 위치한 시간을 저장
int headtime[100][100];
 
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie();
 
    cin >> n >> k;
 
    //사과정보 저장
    int ax, ay;
    for (int i = 0; i < k; i++) {
        cin >> ax >> ay;
        apple[ax - 1][ay - 1= true;
    }
 
    int l;
    cin >> l;
    int t;
    char c;
 
    //방향 회전 정보를 저장
    vector<pair<intchar>> vt;
    for (int i = 0; i < l; i++) {
        cin >> t;
        cin >> c;
        vt.push_back(make_pair(t,c));
    }
 
    int time = 0;
 
    //방향 회전정보를 이용하기 위한 인덱스
    int index = 0;
 
    //초기 방향
    int dir = 0;
 
    //초기 길이
    int len = 1;
 
    //초기 위치는 좌측 맨위쪽
    int x = 0;
    int y = 0;
    while (true) {
        //먼저 시간증가, 길이 증가, 머리 앞칸으로 이동
        time++;
        len += 1;
        int nx = x + dx[dir];
        int ny = y + dy[dir];
        
        
        //벽에 부딪힘
        if (nx < 0 || ny < 0 || nx >= n || ny >= n) break;
 
        //몸에 부딪힘 ((현재 시간 - 몸길이)가 이동할 칸에 머리가 있었던 시간보다 작으면 몸에 부딪힌 것 이다)
        if (headtime[nx][ny] != 0 && ((time - len) < headtime[nx][ny])) break;
 
        //이동한 칸에 현재 시간을 저장
        headtime[nx][ny] = time;
 
        //사과가 있는지 검사
        if (apple[nx][ny]) {
            apple[nx][ny] = false;
        }
        else {
            len -= 1;
        }
 
 
        //l번만큼 방향이동을 한다.
        if (index < l) {
            //현재시간이 방향을 회전해야하는 시간이다
            if (time == vt[index].first) {
                if (vt[index].second == 'D') {
                    dir = (dir + 1) % 4;
                }
                else if (vt[index].second == 'L') {
                    dir = (dir + 3) % 4;
                }
 
                //방향 전환했으면 index증가 (다음 방향 정보를 이용하기 위해)
                index++;
            }
        }
        
        //현재 좌표를 머리가 이동한 칸의 좌표로 변경
        x = nx;
        y = ny;
    }
 
 
 
    cout << time << '\n';
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2234. 성곽  (0) 2019.08.13
[BOJ] 11559. Puyo Puyo  (0) 2019.08.08
[BOJ] 15683. 감시  (0) 2019.08.05
[BOJ] 14500. 테트로미노  (0) 2019.08.04
[BOJ] 14499. 주사위 굴리기  (0) 2019.08.04

+ Recent posts