S E P H ' S

[Java] BJ.17822 원판 돌리기 본문

Algorithm/BackJoon

[Java] BJ.17822 원판 돌리기

yoseph0310 2023. 3. 28. 18:17

 

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀

www.acmicpc.net

 

풀이

  • 시계 방향, 반시계 방향으로 원판을 회전하는 기능
  • 인접수를 찾는 기능
  • 평균을 구해 평균에 따라 원판의 수를 업데이트 하는 기능

회전하는 기능은 쉽게 구현해냈고 인접수를 찾아 없애는 것은 문제의 조건에 따라 인접한 수가 같으면 그 좌표값들을 Set에 Point 객체에 담아 넣었다. 그리고 인접수를 찾는 과정이 모두 끝나면 Set 담긴 객체들의 좌표에 해당하는 곳을 0으로 업데이트 해준 다음 평균값에 따라 계산을 해준 다음 원판의 모든 수의 합을 구하면 되는 어떻게 보면 정말 조건만 맞게 따라가면 쉬울 수도 있는 문제였다.

내 문제는 평균보다 큰 값과 작은 값에 각각 다르게 연산을 해주어야 하는데 평균을 int로 해버려서 정확한 대소 비교를 해내지 못했다. (이것 때문에 몇시간을 엄한데를 디버깅했다...) 요즘 자잘한 실수가 많아지는데 더욱 꼼꼼하게 기능별로 주의해야 할 것들을 생각해서 구현해야겠다는 생각을 하게 됐다. 그래도 요즘 로직을 구상하고 구현까지 시간이 많이 단축된 것 같아 자신감이 많이 붙었다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;

public class Main {

    static int N, M, T, ans;
    static int[][] circle;
    static HashSet<Point> set = new HashSet<>();

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        T = Integer.parseInt(st.nextToken());

        circle = new int[N + 1][M];    // xi 의 배수 번쩨 원판을 돌려하기 때문에 입력값 그대로 인덱스를 쓴다.

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

        int x, d, k;
        for (int i = 0; i < T; i++) {
            st = new StringTokenizer(br.readLine());

            x = Integer.parseInt(st.nextToken());
            d = Integer.parseInt(st.nextToken());
            k = Integer.parseInt(st.nextToken());

            // 회전
            rotate(x, d, k);

            // 인접수 찾아 삭제하기
            findSameNumber();

            if (set.size() != 0) {
                for (Point p: set) {
                    circle[p.x][p.y] = 0;
                }
            } else {
                calculate();
            }

        }

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

        System.out.println(ans);
    }

    static void calculate() {
        double sum = 0;
        double num = 0;
        double avg = 0;

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

        if (num != 0) {
            avg = sum / num;
        }

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

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

    static void findSameNumber() {
        set.clear();

        // 같은 안 원안에서의 인접수 찾기
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < M - 1; j++) {
                if (circle[i][j] == 0) continue;

                if (j == 0) {
                    if (circle[i][0] == circle[i][M - 1]) {
                        set.add(new Point(i, 0));
                        set.add(new Point(i, M - 1));
                    }
                }

                if (circle[i][j] == circle[i][j + 1]) {
                    set.add(new Point(i, j));
                    set.add(new Point(i, j + 1));
                }
            }
        }

        // 다른 두 원의 접점에서 인접수 찾기
        for (int i = 1; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (circle[i][j] == 0) continue;

                if (circle[i][j] == circle[i + 1][j]) {
                    set.add(new Point(i, j));
                    set.add(new Point(i + 1, j));

                }
            }
        }



    }

    static void rotate(int x, int d, int k) {
        // 원판을 회전시킨다.
        for (int i = 1; i <= N; i++) {
            // x의 배수인 원판을
            if (i % x == 0) {

                // d 방향(0 - 시계, 1 - 반시계)으로 k 번 회전
                for (int j = 0; j < k; j++) {
                    if (d == 0) {

                        int temp = circle[i][M - 1];

                        for (int l = M - 1; l > 0; l--) {
                            circle[i][l] = circle[i][l - 1];
                        }
                        circle[i][0] = temp;
                    } else {

                        int temp = circle[i][0];

                        for (int l = 0; l < M - 1; l++) {
                            circle[i][l] = circle[i][l + 1];
                        }
                        circle[i][M - 1] = temp;
                    }
                }

            }
        }

    }

    static class Point {
        int x, y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

 

 

'Algorithm > BackJoon' 카테고리의 다른 글

[Java] BJ.10986 나머지 합  (0) 2023.01.21
[Java] BJ.10816 숫자 카드2  (0) 2022.07.03
[Python] BJ.10815 숫자카드  (0) 2022.06.14
[Java] BJ.10815 숫자 카드  (0) 2022.06.14
[Python] BJ.10989 수 정렬하기 3  (0) 2022.06.13