[백준] 17822 - 원판 돌리기 (java)

HaYeong Jang·2021년 4월 24일
0

[백준] 알고리즘

목록 보기
56/62
post-thumbnail

문제

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

코드

import java.io.*;
import java.util.*;

public class Main {
	static int N, M, x, d, k;
	static int[][] circle;
	static boolean[][] erase;
	static long answer = 0;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		int T = Integer.parseInt(st.nextToken()); // 회전 수
		circle = new int[N + 1][M + 1];

		for (int i = 1; i <= N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 1; j <= M; j++) {
				circle[i][j] = Integer.parseInt(st.nextToken());
			}
		}

		while (T-- > 0) {
			st = new StringTokenizer(br.readLine());
			x = Integer.parseInt(st.nextToken()); // x의 배수
			d = Integer.parseInt(st.nextToken()); // d 방향으로
			k = Integer.parseInt(st.nextToken()); // k칸 회전

			erase = new boolean[N + 1][M + 1];

			for (int i = x; i <= N; i = i + x) {
				rotation(i, d);
			}
			checkAdj();
			erase();
		}

		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				if (circle[i][j] > 0) {
					answer += circle[i][j];
				}
			}
		}

		bw.write(answer + "\n");
		bw.close();
		br.close();
	}

	public static void rotation(int row, int d) {
		if (d == 0) { // 시계방향
			for (int i = 1; i <= k; i++) {
				int temp = circle[row][M];
				for (int j = M; j > 1; j--) {
					circle[row][j] = circle[row][j - 1];
				}
				circle[row][1] = temp;
			}
		} else if (d == 1) { // 반시계방향
			for (int i = 1; i <= k; i++) {
				int temp = circle[row][1];
				for (int j = 1; j < M; j++) {
					circle[row][j] = circle[row][j + 1];
				}
				circle[row][M] = temp;
			}
		}
	}

	public static void checkAdj() {
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				if (circle[i][j] == 0) {
					continue;
				}

				// 원판 내에서 확인
				if (circle[i][j] == circle[i][(j + (M - 1)) % M]) {
					erase[i][j] = true;
					erase[i][(j + (M - 1)) % M] = true;
				}
				if (circle[i][j] == circle[i][(j + 1) % M]) {
					erase[i][j] = true;
					erase[i][(j + 1) % M] = true;
				}

				// 다른 이웃한 원판 확인
				if (i == 1) { // 첫번째 원판
					if (circle[i][j] == circle[i + 1][j]) {
						erase[i][j] = true;
						erase[i + 1][j] = true;
					}
				} else if (i == N) { // 마지막 원판
					if (circle[i][j] == circle[i - 1][j]) {
						erase[i][j] = true;
						erase[i - 1][j] = true;
					}
				} else {
					if (circle[i][j] == circle[i - 1][j]) {
						erase[i][j] = true;
						erase[i - 1][j] = true;
					}
					if (circle[i][j] == circle[i + 1][j]) {
						erase[i][j] = true;
						erase[i + 1][j] = true;
					}
				}
			}
		}
	}

	public static void erase() {
		boolean flag = false;
		int sum = 0;
		int cnt = 0;

		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				if (circle[i][j] == 0) {
					continue;
				}

				if (erase[i][j]) {
					circle[i][j] = 0;
					flag = true;
				} else {
					sum += circle[i][j];
					cnt++;
				}
			}
		}

		// 인접하면서 수가 같은 것이 없는 경우
		if (!flag) {
			float avg = (float) sum / cnt;

			for (int i = 1; i <= N; i++) {
				for (int j = 1; j <= M; j++) {
					if (circle[i][j] == 0) {
						continue;
					}

					if (circle[i][j] > avg) {
						circle[i][j]--;
					} else if (circle[i][j] < avg) {
						circle[i][j]++;
					}
				}
			}
		}
	}
}

정리

circle[][]: 원판
erase[][]: 지울 곳인지

알고리즘
rotation(row, d): row 번째 원판을 d 방향으로 돌린다.
checkAdj(): 1. 원판 내에서 확인 2. 이웃한 원판 확인
하며 같은 값을 erase[][]에 기록
erase(): erase[][]==true인 곳을 지운다. 지울 곳이 없는 경우, avg보다 작은 곳은 circle++ avg보다 큰 곳은 circle--

profile
기억하기 위해 기록하는 개발로그👣

0개의 댓글