본문 바로가기

그래프/BFS

포탑 부수기

https://www.codetree.ai/training-field/frequent-problems/problems/destroy-the-turret/description?page=1&pageSize=20 

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

1. 최단 거리이므로 BFS를 쓰자.

split_damage를 위해서는

BFS의 경로를 이용!

경로를 저장하는 배열을 만들어 경로를 저장해가면서 BFS를 진행!

숨바꼭질 문제, DSLR 문제에서 풀었다.

 

우/하/좌/상의 우선순위대로 먼저 움직인 경로가 선택되므로

dx[], dy[]도 우/하/좌/상 순으로 만든다.

 

실수!

공격하는 타워 좌표를 dx, dy로 놓았다가

위의 배열과 충돌이 일어났었다. 

변수 설정 조심하자!

 

2. 맵이 이어질 때 nx, ny 처리법

가장자리에서 막힌 방향으로 진행하고자 한다면, 반대편으로 나옵니다.

https://larc-en-ciel.tistory.com/206

 

마법사 상어와 파이어볼 + 비바라기

https://www.acmicpc.net/problem/20056 20056번: 마법사 상어와 파이어볼 첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri,

larc-en-ciel.tistory.com

파이어볼 문제에서 배웠다. 모둘러 연산을 이용한다.

 

int nx = (x + dx[k] + n) % n;
int ny = (y + dy[k] + m) % m;

 

n과 m을 더해주고 % 연산을 해주면 된다.

 

3. 시간 초과가 나왔다.

Reason 1. 맨 처음 풀이는 삼중 for문을 이용했었다.

map의 이중 포문 안에서 하나하나 tower의 row, col과 비교하는 미친 짓을 했다.

왜? 시간이라는 변수가 있으니..

 

하지만 간단하게 해결 가능했다.

int rec[15][15];

시간 기록 이차원 배열을 만들어서

tower.clear()를 한 다음

map 값이랑 rec 값을 tower에 넣어주면 됐다!

공격자 포탑은

rec[tower[0].row][tower[0].col] = t;

 

Reason 2.

BFS 경로를 저장할 때 이차원 벡터에 pair를 넣어서 사용했다.

매우 시간이 오래 걸렸다. 

그냥 x 좌표용 이차원 배열, y 좌표용 이차원 배열을 만드니 

시간 초과가 해결 되었다.

 

<소스코드>

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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
int dx[] = { 010-1 };
int dy[] = { 10-10 };
 
int canon_x[] = { -1,-1-1001,11 };
int canon_y[] = { -1,01-11-101 };
 
int map[15][15];
int rec[15][15];
bool visited[15][15];
 
// 공격과 관련이 있었는가를 체크
bool related[15][15];
 
int back_x[15][15];
int back_y[15][15];
 
int n, m, k;
 
struct t_info
{
    int row;
    int col;
    int jikan;
    int power;
};
 
// sort에서는 반대
bool operator < (const t_info& a, const t_info& b)
{
    if (a.power == b.power)
    {
        if (a.jikan == b.jikan)
        {
            if ((a.row + a.col) == (b.row + b.col))
            {
                return a.col > b.col;
            }
            return (a.row + a.col) > (b.row + b.col);
        }
        return a.jikan > b.jikan;
    }
    return a.power < b.power;
}
 
vector<t_info> tower;
 
bool laser()
{
    int s_x = tower[0].row;
    int s_y = tower[0].col;
    int d_x = tower[tower.size() - 1].row;
    int d_y = tower[tower.size() - 1].col;
    // 공격자와 공격 당하는 사람은 연관
    related[s_x][s_y] = true;
    related[d_x][d_y] = true;
    int split_damage = tower[0].power / 2;
 
    // 경로를 저장하는 bfs
    queue<pair<intint>> q;
    q.push(make_pair(s_x, s_y));
    visited[s_x][s_y] = true;
 
    while (!q.empty())
    {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        if (x == d_x && y == d_y)
            break;
 
        for (int k = 0; k < 4; k++)
        {
            int nx = (x + dx[k] + n) % n;
            int ny = (y + dy[k] + m) % m;
 
            if (!visited[nx][ny] && map[nx][ny] != 0)
            {
                visited[nx][ny] = true;
                q.push(make_pair(nx, ny));
                // 이렇게 경로를 저장한다
                back_x[nx][ny] = x;
                back_y[nx][ny] = y;
            }
        }
    }
 
    // 경로를 따라간다
    if (visited[d_x][d_y])
    {
        map[d_x][d_y] -= tower[0].power;
        if (map[d_x][d_y] < 0)
            map[d_x][d_y] = 0;
 
 
        int i = back_x[d_x][d_y];
        int j = back_y[d_x][d_y];
 
        while (true)
        {
            if (i == s_x && j == s_y)
                break;
            map[i][j] -= split_damage;
            if (map[i][j] < 0)
                map[i][j] = 0;
            related[i][j] = true;
 
            int next_i = back_x[i][j];
            int next_j = back_y[i][j];
 
            i = next_i;
            j = next_j;
        }
        return true;
    }
    else
        return false;
}
 
void canon()
{
    int d_x = tower[tower.size() - 1].row;
    int d_y = tower[tower.size() - 1].col;
    int split_damage = tower[0].power / 2;
 
    related[tower[0].row][tower[0].col] = true;
    related[d_x][d_y] = true;
 
    map[d_x][d_y] -= tower[0].power;
    if (map[d_x][d_y] < 0)
        map[d_x][d_y] = 0;
 
    for (int k = 0; k < 8; k++)
    {
        int nx = (d_x + canon_x[k] + n) % n;
        int ny = (d_y + canon_y[k] + m) % m;
 
        // 공격자는 영향을 받지 않음
        if (nx == tower[0].row && ny == tower[0].col)
            continue;
        if (map[nx][ny] > 0)
        {
            map[nx][ny] -= split_damage;
            related[nx][ny] = true;
            if (map[nx][ny] < 0)
                map[nx][ny] = 0;
        }
    }
}
 
void duhagi()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (map[i][j] != 0 && related[i][j] == false)
                map[i][j] += 1;
        }
    }
}
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> n >> m >> k;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> map[i][j];
            if (map[i][j] != 0)
                tower.push_back({ i,j,0,map[i][j] });
        }
    }
    memset(rec, 0sizeof(rec));
    for (int t = 1; t <= k; t++)
    {
        tower.clear();
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (map[i][j] > 0)
                {
                    tower.push_back({ i,j,rec[i][j], map[i][j] });
                }
            }
        }
 
        if (tower.size() <= 1)
            break;
 
        memset(visited, falsesizeof(visited));
        memset(related, falsesizeof(related));
 
        sort(tower.begin(), tower.end());
        tower[0].power += n + m;
        map[tower[0].row][tower[0].col] = tower[0].power;
        // 공격을 한다면 rec에 t를 저장
        rec[tower[0].row][tower[0].col] = t;
 
        bool chk = laser();
        if (!chk)
            canon();
 
        // 공격과 관련없는 포탑들 +1
        duhagi();
    }
 
    int ans = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            ans = max(ans, map[i][j]);
 
    cout << ans;
    return 0;
}
cs

'그래프 > BFS' 카테고리의 다른 글

효율적인 해킹  (2) 2024.01.04
코드트리 빵  (0) 2023.10.14
퍼즐  (0) 2023.09.08
인구 이동  (0) 2023.09.07
물통  (0) 2023.09.01