본문으로 바로가기

굉장히 놀랍게도 어른 상어 이후의 상어 시리즈가 있었다! 마법사 상어와 파이어볼의 연장선 같은 느낌이 나는 문제였는데, 맵을 넘어가는 구름이 이동 시 모듈러 연산을 하는 부분이 그러했다. 지난번과 같이 수학적으로 한줄로 풀어낼까 하다가, 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;
		}

	}
}