Post

[PCCP 기출문제] 2번 / 석유 시추

[PCCP 기출문제] 2번 / 석유 시추

🙋‍♂️ 들어가며

이번 문제는 시간복잡도를 생각하지 않으면 틀리는 문제였다

나는 우선 한번 BFS를 활용하여 3중 반복문

r = 0, r < 1
c = 0; c < col
k = 0; k < row

여기서 맨 첫 행에서 [0][0] ~ [0][col] 동안 확인하고 그때마다 각각 시추관의 크기를 0 ~ row까지 반복해서 점검하고자했다.

이 테스트케이스에서 맞길래 제출했는데 시간초과가 나서 오류였다.

일단 틀렸던 코드는 다음과 같다

❌틀린 코드 (시간초과)

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
import java.util.Queue;
import java.util.LinkedList;


class Solution {
    static int[] dr = {-1,1,0,0};
    static int[] dc = {0,0,-1,1};
    static int max_oil = Integer.MIN_VALUE;


    public int solution(int[][] land) {

        // 열, 행
        int col = land[0].length;
        int row = land.length;

        for (int r = 0; r < 1; r++) {
            for (int c = 0; c < col; c++) {
                // 방문 맵
                boolean[][] visited = new boolean[row][col];

                // 임시횟수 (합산용)
                int temp_cnt = 0;

                // 시추관
                for (int k = 0; k < row; k++) {
                    // 최적화 (만약 방문했다면 skip)
                    if (visited[k][c]) continue;

                    // 빈땅이면 통과
                    if (land[k][c] == 0) continue;

                    // 방문 안했으면 방문처리후 temp_cnt에 추가, 그리고 q에 삽입
                    visited[k][c] = true;
                    temp_cnt++;
                    Queue<int[]> q = new LinkedList<>();
                    q.add(new int[] {k, c});

                    while (!q.isEmpty()) {
                        int[] cur_pos = q.poll();
                        int cr = cur_pos[0];
                        int cc = cur_pos[1];

                        for (int d = 0; d < 4; d++) {
                            int nr = cr + dr[d];
                            int nc = cc + dc[d];

                            // 범위 확인
                            if (nr < 0 || nr >= row || nc < 0 || nc >= col) continue;

                            // 다음 좌표가 빈땅이거나, 방문했으면 skip
                            if (land[nr][nc] == 0 || visited[nr][nc]) continue;

                            // 방문 안했으면 visitied 후 -> temp_cnt++ 그리고 q에 추가
                            visited[nr][nc] = true;
                            temp_cnt++;
                            q.add(new int[] {nr, nc});
                        }
                    }
                }
                // 비교
                max_oil = Math.max(max_oil, temp_cnt);

            }
        }


        return max_oil;
    }
}

틀린 이유를 알아보니 반례로 최악의 실행시간이 다음과 같더라

500 * 250000 * 500

즉 시간초과겠다.



🤔 다른 방법을 생각해보자

그렇다면 다른 방법을 생각해보니 완전탐색이 있더라

사진 1

Desktop View

사진 2

Desktop View

사진에 보는것처럼 노란색 점 을 현재 좌표로 가정하자.

초록색은 cnt++ 처리

빨간색 체크는 현재좌표가 석유와 이어져있는 column 이다.

각 사진마다 land[0][3], 그리고 land[4][6] 일때 HashSet에 석유가 있는 열들을 추가하여

oil_by_col = new int[열의 크기] 를 활용할 수 있지않을까?

이런 식으로 말이다

1
2
3
for (int col_idx : set) {
	oil_by_col[col_idx] += cnt;
}

위 사진 기준으로 land[0][3] 일때는 set에 3,4,5,6 추가
land[4][6] 일땐 set에 6,7 이 추가되겠다.

그러면 중복이 되지 않고도 좌표를 1개씩 완전탐색 하여 위의 배열에 추가할 수 있겠다.

이때의 최악의 실행시간은 다음과 같겠다

1
(500 * 500 * 4) + O(500)

-> 아 1억 이내 연산이라 시간초과 안나네 (good)



✅ 정답

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.util.HashSet;
import java.util.Set;

import java.util.Queue;
import java.util.LinkedList;


class Solution {
    static int[] dr = {-1,1,0,0};
    static int[] dc = {0,0,-1,1};
    static int max_oil = Integer.MIN_VALUE;
    static boolean[][] visited;
    static int row, col;
    
    public int solution(int[][] land) {
        row = land.length;
        col = land[0].length;
        visited = new boolean[row][col];
        
        // 완전탐색시 각 열마다 방문안한 좌표를 합산해주기 위한 배열
        int[] oil_by_col = new int[col];
        
        for (int r = 0; r < row; r++) {
            for (int c = 0; c < col; c++) {
                // 만약 방문 안했고 + 석유라면
                if (!visited[r][c] && land[r][c] == 1) {
                    BFS(r, c, oil_by_col, land);
                }
            }
        }
        
        // 최대 비교
        for (int i : oil_by_col) {
            max_oil = Math.max(i, max_oil);
        }
        
        return max_oil;
    }
    
    
    
    
    
    static void BFS(int r, int c, int[] oil_by_col, int[][] land) {
        Queue<int[]> q = new LinkedList<>();
        
        // 석유덩어리가 겹치는 열을 oil_by_col에 반복문으로 저장해주기위해 Set 사용
        Set<Integer> set = new HashSet<>();
        
        int cnt = 0;
        
        // 지금 현재 좌표는 방문 안한 석유니까 -> cnt++;
        // 그리고 현재좌표의 열도 석유랑 맞닥드렸으니 set에 추가하자
        cnt++;
        set.add(c);
        
        visited[r][c] = true;
        q.add(new int[] {r, c});
        
        
        // 확인
        while (!q.isEmpty()) {
            int[] cur_pos = q.poll();
            int cr = cur_pos[0];
            int cc = cur_pos[1];
            for (int d = 0; d < 4; d++) {
                int nr = cr + dr[d];
                int nc = cc + dc[d];
                
                // 범위 밖이면 skip
                if (nr < 0 || nr >= row || nc < 0 || nc >= col) continue;
                
                // 다음좌표를 방문했거나, 빈땅이면 skip
                if (visited[nr][nc] || land[nr][nc] == 0) continue;
                
                // 미방문했다면 횟수 추가하고 방문처리
                visited[nr][nc] = true;
                cnt++;
                
                // 만약 col = 8일때, land[nr][nc] == 1
                // 그리고 그때의 nc가  0, 1, 4 -> set에 추가
                set.add(nc);
                q.add(new int[]{nr, nc});
            } 
        }
        
        // oil_by_col 에 set에 들은 열번호의 갯수만큼 반복하여 cnt 추가
        for (int col_idx : set) {
            oil_by_col[col_idx] += cnt;
        }
        
        
    }
    
    
    
}
This post is licensed under CC BY 4.0 by the author.
3D GIF

Trending Tags

도움이 필요하면
나를 눌러 구리🐻
챗봇
너굴
bot
어서와 구리 ʕ ·ᴥ·ʔ
무엇이 필요하셔 구리?

Trending Tags

도움이 필요하면
나를 눌러 구리🐻
챗봇
너굴
bot
어서와 구리 ʕ ·ᴥ·ʔ
무엇이 필요하셔 구리?