알고리즘 문제 풀이/BOJ

[backjoon]14500 테트로미노 java

v 2022. 4. 11. 18:30

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

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변

www.acmicpc.net

돌린 배열을 바탕으로 다 확인해야하는데 이게 어떻게 Gold5밖에 안 되는지 처음엔 말이 안 된다고 생각했는데, 가만 보면 금방 풀 수 있다.

폴리오미노라는 도형들을 보면 공통적으로 4개임을 알 수 있다. 또한, ㅜ 모양을 제외하고는 한 점에서 중복되지 않고 3번 더 갔을 때의 경로들임을 아는 것이 문제의 포인트!

즉, ㅜ 모양을 제외하고는 모든 모양이 4방향으로 갈 수 있는 모든 경로임을 알 수 있다.

따라서 모든 지점을 중복되지 않게 모두 확인해가면서 제일 큰 값을 구해주면 된다.

ㅜ모양은 한 점을 기준으로 될 수 있는 모든 방향 ㅜ/ㅗ/ㅓ/ㅏ의 방향들을 기록하고 순서대로 방문해서 계산할 수 있는 값들을 더하는 방식으로 풀이!

BFS를 이용하면 전체 방문이 불가능하고! 최대 map의 값이 500, 길이가 4를 확인했을 때 DFS를 통해 값을 구할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import java.io.*;
import java.util.*;
 
public class Main {
    static int N, M, answer;
    static int[][] map;
    static int[][] dirs = { { 10 }, { -10 }, { 01 }, { 0-1 } };
    static boolean[][] marked;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        map = new int[N][M];
        answer = 0;
        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());
            }
        }
        
        // << 중복해서 방문하지 않도록 꼭꼭 방문처리 잘하기. 위치도 중요함>>
        for (int i = 0; i < N; i++) {
            marked = new boolean[N][M];
            for (int j = 0; j < M; j++) {
                marked[i][j] = true;
                dfs(i, j, 1, map[i][j]);
                unique(i, j);
            }
        }
        System.out.println(answer);
    }
    
    //<< 특이한 모양은 값을 방향들을 구해줘서 풀이해준다. -> 경우의 수가 크지 않기에 다 탐색해도 됨.>>
    public static void unique(int row, int col) {
        int[][][] dirs = { { { 1-1 }, { 10 }, { 11 } }, // ㅗ
                { { 10 }, { 11 }, { 20 } }, // ㅏ
                { { 0-1 }, { 01 }, { 10 } }, // ㅜ
                { { 10 }, { 1-1 }, { 20 } } // ㅓ
        };
        for (int turn = 0; turn < 4; turn++) {
            int sum = map[row][col];
            for (int d = 0; d < 3; d++) {
                int nextR = row + dirs[turn][d][0];
                int nextC = col + dirs[turn][d][1];
                if (nextR < 0 || nextC < 0 || nextR >= N || nextC >= M)
                    break;
                sum += map[nextR][nextC];
            }
            answer = Math.max(sum, answer);
        }
    }
 
    //<< 길이가 4인 것들만 모아서 최대 거리 확인하기>>
    public static void dfs(int row, int col, int lengthint sum) {
        if (length == 4) {
            answer = Math.max(sum, answer);
            return;
        }
 
        for (int d = 0; d < 4; d++) {
            int nextR = row + dirs[d][0];
            int nextC = col + dirs[d][1];
            if (nextR < 0 || nextC < 0 || nextR >= N || nextC >= M)
                continue;
            if (marked[nextR][nextC])
                continue;
            marked[nextR][nextC] = true;
            dfs(nextR, nextC, length + 1, sum + map[nextR][nextC]);
            marked[nextR][nextC] = false;
        }
    }
}
cs

 

풀이 중에 느닷없이 시간초과에 걸렸었는데 방문 확인하는 배열을 시작 값이 움직일 때마다 초기화해줘서 그랬다.

초기화를 쉽게 하지 말자.

반응형