[BJ]테트로미노 _14500

2025. 4. 17. 15:37알고리즘 풀이

 

풀이 핵심

도형을 회전시키는 방법
int[] position은 r,c 정보를 담고 있을 때, (r,c) -> (c, size - r - 1)
여기서 size는 어떤 정사각형에 도형이 담겨있다고 생각할 때 한변의 길이를 의미한다.
위 공식을 사용하면 회전을 하고, 만약 ㅗ 모양이 회전해서 ㅏ 모양이 되었을 때
[ (0,1), (1,0), (1,1), (1,2) ] => [ (0,1), (1,1), (1,2), (2,1) ] 이된다.
여기서 setStartPoint함수가 하는 역할은 정사각형 안에 도형을 왼쪽 끝에 맞출 수 있도록 설정하는 것이다. 
[ (0,1), (1,1), (1,2), (2,1) ] => [ (0,0), (1,0), (1,1), (2,0) ]

 

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

public class Main {
    static int N,M, map[][], ans=0;
    static Ttrno[] ttrnos;
 
    public static void main(String[] args) throws IOException {
        // 입력 처리
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        map = new int[N][M];
        // 종이 입력받기.
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        // 테트리노 모양,회전,반전 설정
        initTtrno();



        // 테트리노 모양 별로 맵을 순회하면서 시뮬레이션해본다.
        for (int i = 0; i < ttrnos.length; i++) {
            Ttrno curTtrno = ttrnos[i];

            if(!curTtrno.doInversion && !curTtrno.doRevor){ // 돌리거나 반전이 필요 없을때 1번만 돌리기.
                simul(curTtrno.position);
            }else{

                if(curTtrno.doRevor){ // 회전 해봐야하는거면 회전하고 시뮬 재실행
                    for (int j = 0; j < 4; j++) {

                        letRevor(curTtrno.position);
                        // 초기 시작점 맞추기.

                        setStartPoint(curTtrno.position);

                        simul(curTtrno.position);
                    }
                }
                // 반전도 해야하면 해보기.
                if(curTtrno.doInversion){
                    letInversion(curTtrno.position);
                    // 회전 시키면서 또 시뮬
                    for (int j = 0; j < 4; j++) {
                        letRevor(curTtrno.position);
                        setStartPoint(curTtrno.position);
                        simul(curTtrno.position);
                    }
                }
            }


        }

        System.out.println(ans);

    }



    public static void simul(int[][] position){
        int sum =0 ;

        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                int tmpSum=0;
                // 모든 지점에서 도형모양으로 이동하면서 합을 계산한다.
                for (int k = 0; k < position.length; k++) {
                    int ni = i+position[k][0];
                    int nj = j+position[k][1];
                    if(!isOut(ni,nj)) {
                        tmpSum+=map[ni][nj];

                    }else {
                        tmpSum = 0;
                        break;
                    }

                }
                // 테트리노 모양대로 이동했을 때 계산된 합의 최대값을 갱신
                sum = Math.max(sum,tmpSum);
            }
        }
        // 최대를 답에 갱신.
        ans = Math.max(ans,sum);
    }

    public static void letRevor(int[][] position){
        int tSize = getTSize(position);

        for (int i = 0; i < position.length; i++) {
            int row = position[i][0];
            int col = position[i][1];
            // 회전 공식 적용
            int rRow = col;
            int rCol = tSize - row - 1;
            position[i][0] = rRow;
            position[i][1] = rCol;
        }

    }

    private static int getTSize(int[][] position) {
        int ts=0;
        for (int i = 0; i < position.length; i++) {
            ts = Math.max(ts, Math.max(position[i][0], position[i][1]));
        }
        return ts+1;
    }

    public static void letInversion(int[][] position){
        int size = position[0].length;

        for (int i = 0; i < position.length; i++) {
            int col = position[i][1];
            // 반전 공식 적용
            position[i][1] = size - col -1;
        }
    }


    private static void initTtrno() {
        ttrnos = new Ttrno[6];
        // 네모 : 회전, 반전 불필요.
        int[][] position = new int[][] {{0,0},{0,1},{1,0},{1,1}};
        ttrnos[0] = new Ttrno(false,false,position);
        // 1자 1번만 돌리면 되기 때문에 2개 넣을 것 모양 : ㅡ,ㅣ
        position = new int[][] {{0,0},{0,1},{0,2},{0,3}};
        ttrnos[1] = new Ttrno(false,false,position);
        position = new int[][] {{0,0},{1,0},{2,0},{3,0}};
        ttrnos[2] = new Ttrno(false,false,position);

        // ㄴ모양 : 회전 반전 둘다 필요
        position = new int[][] {{0,0},{1,0},{2,0},{2,1}};
        ttrnos[3] = new Ttrno(true,true,position);
        ttrnos[3].me=true;

        // ㅜ모양 : 회전만 필요
        position = new int[][] {{0,0},{0,1},{0,2},{1,1}};
        ttrnos[4] = new Ttrno(true,false,position);

        // 나머지 1개 모양은 회전, 반전 둘 다 필요.
        position = new int[][] {{0,0},{1,0},{1,1},{2,1}};
        ttrnos[5] = new Ttrno(true,true,position);
    }

    /**
     * 회전 : (r,c) -> (c, max(colSize, rowSize)-r-1);
     * 반전 : (r,c) -> (r, max(colSize) - c-1);
     * */
    static class Ttrno{
        // 회전해야하는지, 반전해야하는지
        boolean doRevor, doInversion,me;
        int[][] position = new int[4][2];
        public Ttrno(boolean doRevor, boolean doInversion, int[][] position){
            this.doRevor = doRevor;
            this.doInversion = doInversion;
            this.position = position;
        }
    }
    // 회전시킨 경우는 시작점을 (0,?) or (?,0) 으로 맞추기.
    public static void setStartPoint(int[][] position){

        int minR = 2000;
        int minC = 2000;
        for (int i = 0; i < position.length; i++) {
            minR = Math.min(minR,position[i][0]);
            minC = Math.min(minC,position[i][1]);
        }


        for (int i = 0; i < position.length; i++) {
            position[i][0]-=minR;
            position[i][1]-=minC;
        }
    }

    public static boolean isOut(int ni, int nj){
        return ni < 0 || ni >= N || nj < 0 || nj >= M;
    }
}

'알고리즘 풀이' 카테고리의 다른 글

[BJ]_점수따먹기  (0) 2025.04.18
PG_퍼즐 조각 채우기  (0) 2025.01.04
[백준]17071_숨바꼭질5  (2) 2024.11.02
[백준]6549_히스토그램에서 가장 큰 직사각형  (1) 2024.10.30
[백준]18809_Gaaaaaaaaaarden(java)  (1) 2024.10.30