굉장히 놀랍게도 어른 상어 이후의 상어 시리즈가 있었다! 마법사 상어와 파이어볼의 연장선 같은 느낌이 나는 문제였는데, 맵을 넘어가는 구름이 이동 시 모듈러 연산을 하는 부분이 그러했다. 지난번과 같이 수학적으로 한줄로 풀어낼까 하다가, mod 함수를 따로 빼서 두는 것이 가독성이 좋을 것 같아 이번엔 그러한 방식으로 구현해보았다.
구현 방식은 문제에 주어진 것을 그대로 구현하면 된다.
1. 모든 구름이 di 방향으로 si칸 이동한다.
private static void moveCloud() {
Direc d = direcs.poll();
List<Node> tmp = new ArrayList<>();
for (Node n : clouds) {
tmp.add(new Node(mod(n.x + dir[d.d][0] * d.s), mod(n.y + dir[d.d][1] * d.s)));
}
clouds.clear();
clouds.addAll(tmp);
}
2. 각 구름에서 비가 내려 구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가한다.
private static void rainDrop() {
for (Node n : clouds) {
map[n.x][n.y]++;
}
}
3. 구름이 모두 사라진다. ( 특별히 구현하지 않고 코드의 진행 중 자연스럽게 사라집니다.)
4. 2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면, 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
- 이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.
- 예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고, (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.
private static void waterPasteBug() {
for (Node n : clouds) {
map[n.x][n.y] += checkDiagonal(n.x, n.y);
}
}
5. 바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다. 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
private static int checkDiagonal(int x, int y) {
int cnt = 0;
for (int dx : new int[] { 1, -1 }) {
for (int dy : new int[] { 1, -1 }) {
int nx = x + dx;
int ny = y + dy;
if (isValid(nx, ny) && map[nx][ny] != 0) {
cnt++;
}
}
}
return cnt;
}
코드 전문
package samsung;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.function.Function;
public class BOJ_21610_마법사상어와비바라기 {
static int N, M, map[][];
static Function<String, Integer> stoi = Integer::parseInt;
static int[][] dir = new int[][] { { 0, 0 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 },
{ 1, 0 }, { 1, -1 } };
static List<Node> clouds = new ArrayList<>();
static Queue<Direc> direcs = new ArrayDeque<>();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = stoi.apply(st.nextToken());
M = stoi.apply(st.nextToken());
map = new int[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = stoi.apply(st.nextToken());
}
}
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
direcs.add(new Direc(stoi.apply(st.nextToken()), stoi.apply(st.nextToken())));
}
// 초기 구름 위치 추가
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
clouds.add(new Node(N - 2 + i, j));
}
}
while (!direcs.isEmpty()) {
moveCloud();
rainDrop();
waterPasteBug();
createCloud();
}
System.out.println(total());
}
private static int total() {
int cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cnt += map[i][j];
}
}
return cnt;
}
private static void rainDrop() {
for (Node n : clouds) {
map[n.x][n.y]++;
}
}
private static void createCloud() {
List<Node> tmp = new ArrayList<>();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] >= 2) {
if (!clouds.contains(new Node(i, j))) {
tmp.add(new Node(i, j));
map[i][j] -= 2;
}
}
}
}
clouds.clear();
clouds.addAll(tmp);
}
private static void waterPasteBug() {
for (Node n : clouds) {
map[n.x][n.y] += checkDiagonal(n.x, n.y);
}
}
private static int checkDiagonal(int x, int y) {
int cnt = 0;
for (int dx : new int[] { 1, -1 }) {
for (int dy : new int[] { 1, -1 }) {
int nx = x + dx;
int ny = y + dy;
if (isValid(nx, ny) && map[nx][ny] != 0) {
cnt++;
}
}
}
return cnt;
}
private static boolean isValid(int x, int y) {
return 0 <= x && 0 <= y && x < N && y < N;
}
private static void moveCloud() {
Direc d = direcs.poll();
List<Node> tmp = new ArrayList<>();
for (Node n : clouds) {
tmp.add(new Node(mod(n.x + dir[d.d][0] * d.s), mod(n.y + dir[d.d][1] * d.s)));
}
clouds.clear();
clouds.addAll(tmp);
}
private static int mod(int num) {
while (num < 0) {
num += N;
}
return num % N;
}
static class Node {
int x;
int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
Node n = (Node) obj;
return this.x == n.x && this.y == n.y;
}
}
static class Direc {
int d;
int s;
public Direc(int d, int s) {
this.d = d;
this.s = s;
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
백준 2533번 사회망서비스SNS (JAVA) (0) | 2021.07.12 |
---|---|
백준 4195번 친구 네트워크 (JAVA) (0) | 2021.07.12 |
백준 15684번 사다리조작 (JAVA) (0) | 2021.06.27 |
백준 17142번 연구소3 (JAVA) (0) | 2021.06.27 |
백준 17144번 미세먼지안녕 (JAVA) (0) | 2021.06.20 |