본문 바로가기
백준

[백준] code.plus(시뮬레이션과 구현,JAVA)17822번, 원판 돌리기

by 열정적인 이찬형 2022. 8. 10.

문제 링크

 

17822번: 원판 돌리기

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

www.acmicpc.net


주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}

문제 설명


접근 방법

 

이 문제에 핵심은

 

1. T번을 x의 배수 번호판을 시계, 반시계 방향으로 k번 회전합니다.

2. 회전한 후 인접한 숫자가 같으면 해당 숫자들은 사라집니다.

3. 인접한 숫자가 없으면 평균의 값에 따라 +1, -1을 진행합니다.

4. T번을 진행한 뒤에 원판에 남아있는 숫자의 합을 결과로 출력합니다.

 

알고리즘 진행 순서.

 

1. 입력되는 정보들을 저장합니다.

 

2. T번동안 원판 회전 및 숫자 값 변경에 대한 시뮬레이션을 진행합니다.

 

3. T번의 회전이 종료된 뒤에 원판에 수들의 합을 결과로 출력합니다.

 

원판 회전

 

0 : 시계

  1[1]  
4[4]   2[2]
  3[3]  

 

M = 4일 때

시계방향으로 회전은

[i] = [i-1]

i - 1 == 0일 때 : [M]

  4[1]  
3[4]   1[2]
  2[3]  

 

1 : 반 시계

  1[1]  
4[4]   2[2]
  3[3]  

 

M = 4일 때

시계방향으로 회전은

[i] = [i+1]

i + 1 == M+1일 때 : [1]

  2[1]  
1[4]   3[2]
  4[3]

 

 

예제입력 1~4까지 문제에서 진행되는 과정을 자세히 설명하고 있습니다.

 

  • BufferedReader를 사용하여 입력 값을 받았습니다.
  • StringTokenizer를 이용하여 입력된 정보에 대하여 나누었습니다.
  • T번동안 rotation, numCheck, numChange 실행하여 시뮬레이션을 진행합니다.
  • T번 회전 후 원판의 수의 합을 BufferedWriter 저장하였습니다.
  • BufferedWriter에 저장된 결과값을 출력하였습니다.
  • rotation함수는 원판의 시계, 반 시계 방향을 진행합니다.
  • numCheck함수는 원판의 숫자에서 인접한 숫자가 같으면 제거합니다.
  • numChange함수는 numCheck에서 숫자가 제거되지 않았을 때 원판 평균값에 따른 숫자 변경을 진행합니다.

 

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

public class Main {
    static int N,M,T;
    static boolean checkNum;	//인접한 숫자가 사라졌는지 확인하는 변수
    static int[][] circle;	//원판 정보 저장 배열
    public static void main(String[] args) throws IOException {
        //입력값 처리하는 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //결과값 출력하는 BufferedWriter
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        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+2][M+2];
        //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());
        }
        //2. T번동안 원판 회전 및 숫자 값 변경에 대한 시뮬레이션을 진행합니다.
        for(int i = 0;i<T;i++){
            st = new StringTokenizer(br.readLine(), " ");
            int x = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int k = Integer.parseInt(st.nextToken());
            checkNum = false;
            for(int j=x;j<=N;j+=x)		//원판 회전 진행
                rotation(d, j, k);
            numCheck();		//인접한 숫자 확인
            if(!checkNum)	//인접한 숫자 같은 값 없을 때 평균값 관련 숫자 변경
                numChange();
        }
        //3. T번의 회전이 종료된 뒤에 원판에 수들의 합을 결과로 출력합니다.
        int sum = 0;
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++)
                sum+=circle[i][j];
        }
        bw.write(sum + "");	//원판 수의 합 BufferedWriter 저장
        bw.flush();		//결과 출력
        bw.close();
        br.close();
    }
    //원판 회전하는 함수
    static void rotation(int d, int x, int k){
        for(int i=0;i<k;i++){
            if(d ==0){		//시계
                int temp = circle[x][M];	//[M]
                for(int j=M;j>1;j--)	//[i] = [i-1]
                    circle[x][j] = circle[x][j-1];
                circle[x][1] = temp;	//[1] = [M]
            }else{		//반 시계
                int temp = circle[x][1];	//[1]
                for(int j=1;j<M;j++)	//[i] = [i+1]
                    circle[x][j] = circle[x][j+1];
                circle[x][M] = temp;	//[M] = [1] 
            }
        }
    }
    //평균값에 따른 숫자 변경 함수
    static void numChange(){
        int count = 0;
        int sum = 0;
        //모든 숫자 더하기
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++){
                if(circle[i][j]!=0){
                    sum+= circle[i][j];
                    count++;
                }
            }
        }
        float avg = (float)sum/count;	//평균 구하기
        //평균에 따른 값 변경 진행
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++){
                if(circle[i][j]!=0){
                    if(circle[i][j] > avg)
                        circle[i][j]--;
                    else if(circle[i][j] < avg)
                        circle[i][j]++;
                }
            }
        }
    }
    //인접한 숫자에 따른 원판 숫자 제거 함수
    static void numCheck(){
        int[][] tempArr = new int[N+2][M+2];
        for(int i=1;i<=N;i++) {
            for (int j = 1; j <= M; j++) {
                if (circle[i][j] != 0) {
                    tempArr[i][j] = circle[i][j];
                    //왼쪽
                    if (circle[i - 1][j] == circle[i][j]) {
                        tempArr[i][j] = 0;
                        checkNum = true;
                    }
                    //오른쪽
                    if (circle[i + 1][j] == circle[i][j]) {
                        tempArr[i][j] = 0;
                        checkNum = true;
                    }
                    //위쪽
                    int t = j - 1 == 0 ? M : j - 1;
                    if (circle[i][t] == circle[i][j]) {
                        tempArr[i][j] = 0;
                        checkNum = true;
                    }
                    //아래쪽
                    t = j + 1 == M + 1 ? 1 : j + 1;
                    if (circle[i][t] == circle[i][j]) {
                        tempArr[i][j] = 0;
                        checkNum = true;
                    }
                }
            }
        }
        circle = tempArr;
    }
}

댓글