[백준 14500] 테트로미노(Java)

최민길(Gale)·2023년 1월 20일
1

알고리즘

목록 보기
18/172

문제 링크 : https://www.acmicpc.net/problem/14500

이 문제는 백트래킹을 사용하여 풀 수 있습니다.

문제의 특징을 잘 살펴보면, 4개의 블록을 만들 수 있는 경우의 수는 특정 시작점으로부터 4칸 연속으로 이동하는 경우의 수와 같습니다. 따라서 백트래킹으로 현재 위치에서 상하좌우 1칸씩 이동해가면서 4칸이 되었을 때 합의 최댓값을 비교하면 됩니다.

여기서 주의할 점은, 'ㅗ'모양 블록은 위의 경우에 포함되지 않는다는 것입니다. 따라서 이 부분은 직접 수작업으로 처리해주어야 합니다. 크게 ㅗ,ㅏ,ㅜ,ㅓ 모양이 존재하기 때문에, 기준점을 잡아 나머지 블록의 좌표를 구한 후 직접 더해서 비교하시면 됩니다. 이 때 모든 수가 + 연산만 진행하도록 하는 것이 조건을 하나 덜 작성해도 되므로 더 유리합니다. 왜냐하면 기본적으로 반복문에서 맵의 범위까지는 선택하기 때문에 - 연산이 들어가게 될 경우 시작점 위치도 조건을 주어야 하지만 + 연산이 들어가게 될 경우 시작점 위치는 맵의 범위 내에 존재하기 때문에 굳이 설정하지 않아도 되기 때문입니다.

다음은 코드입니다.

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

public class Main{

    static int N,M;
    static int res = 0;
    static int[][] req = new int[501][501];
    static boolean[][] check = new boolean[501][501];
    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,1,0,-1};

    static void backtracking(int y, int x, int cnt, int sum){
        if(cnt==4) {
            if(res<sum) res = sum;
            return;
        }

        for(int i=0;i<4;i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(nx<0 || nx>=M || ny<0 || ny>=N) continue;

            if(!check[ny][nx]){
                check[ny][nx] = true;
                backtracking(ny,nx,cnt+1,sum+req[ny][nx]);
                check[ny][nx] = false;
            }
        }
    }

    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());

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

        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                check[i][j] = true;
                backtracking(i,j,1,req[i][j]);
                check[i][j] = false;

                // 현재 위치에서 ㅗ 모양 블록 가능한 경우의 수 일일히 추가

                // case 1. ㅗ
                // 맨 위 기준 (x,y), (x-1,y+1), (x,y+1), (x+1,y+1)
                if(j+2<M && i+1<N){
                    int sum = req[i][j+1] + req[i+1][j] + req[i+1][j+1] + req[i+1][j+2];
                    if(res<sum) res = sum;
                }

                // case 2. ㅏ
                // 맨 위 기준 (x,y), (x,y+1), (x,y+2), (x+1,y+1)
                if(j+1<M && i+2<N){
                    int sum = req[i][j] + req[i+1][j] + req[i+2][j] + req[i+1][j+1];
                    if(res<sum) res = sum;
                }

                // case 3. ㅜ
                // 맨 위 왼쪽 기준 (x,y), (x+1,y), (x+2,y), (x+1,y+1)
                if(j+2<M && i+1<N){
                    int sum = req[i][j] + req[i][j+1] + req[i][j+2] + req[i+1][j+1];
                    if(res<sum) res = sum;
                }

                // case 4. ㅓ
                // 맨 위 기준 (x,y), (x-1,y+1), (x,y+1), (x,y+2)
                if(j+1<M && i+2<N){
                    int sum = req[i][j+1] + req[i+1][j] + req[i+1][j+1] + req[i+2][j+1];
                    if(res<sum) res = sum;
                }

            }
        }

        System.out.println(res);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글