목차
문제 : Programmers - [PCCP 기출문제] 2번 / 석유 시추
문제 출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
필요 알고리즘
- 탐색 (BFS, DFS 등)
- 약간의 아이디어만 있다면 탐색 알고리즘으로 풀 수 있다.
풀이
우리가 알아야 하는건, 각 열 번호에서 접근 가능한 석유들의 합이다. cnt[X] 라는 배열을 정의해보자. 이건 X 인덱스 열에서 접근 가능한 석유들의 총 합을 뜻한다. 최종적으로 cnt[0] 부터 cnt[m-1] 까지의 값 중 가장 큰 값을 출력하면 될 것이다.
예를들어 아래와 같이 표현될 것이다. 최종적으로 cnt 배열에서 가장 큰 값이 9 이므로 9가 답이다.
---
그럼 이제 cnt[] 에 값을 어떻게 채울 수 있을지 생각해보자.
서로 떨어진 각 석유들의 그룹을 생각해보자. 예를들어 이하 그림에서 색깔 다른게 서로 다른 그룹이다.
해당 석유 그룹의 총 양과, 해당 석유 그룹이 영향을 끼치는 열 인덱스를 어떻게든 알 수 있다고 해보자.
전자를 area, 후자를 candidates 라고 표현하였다. 그럼 아래처럼 알 수 있을꺼다.
그렇다면, 각 그룹에 대해, candidates 번호들을 X에 넣어주면서 cnt[X] += area 를 해주면 cnt 배열을 얻을 수 있을꺼다.
아래처럼 진행될 것이다.
1. 회색 그룹 확인 후
2. 주황색 그룹 확인 후
3. 파란 그룹 확인 후
---
여기까지 이해됬다면, 이제 알아야 하는건 저 area랑 candidates를 어떻게 구하는지만 알면 된다.
우선 area는 간단하다. "아직 살펴보지 않은 석유 그룹을 만났다면, BFS나 DFS를 돌리면서 몇 칸 전진이 가능한지 보면 된다.". 그리고 candidates도 마찬가지다 "area를 구하면서 만난 열 인덱스를 전부 set 같은데 넣어버리면 된다.". 어차피 set은 중복이 안되므로, 중복되서 들어갔더라도 하나만 남을꺼다 (아니면 BFS나 DFS 진행하면서 만난 최소 열 인덱스와 최대 열 인덱스만 남겨둬도 상관없다.)
...
int nr = cr+a; // 다음 확인할 인접한 행 인덱스
int nc = cc+b; // 다음 확인할 인접한 열 인덱스
if (nr<0||nr>=r||nc<0||nc>=c||land[nr][nc]==0) continue;
// 배열 범위를 넘어가거나, 석유가 없는 곳이라면 무시한다.
area++; // 무지성으로 area는 증가시켜주면 된다.
land[nr][nc] = 0; // 이미 본 석유는 없애자. 파라미터로 들어온걸 변경하지 않고싶다면 방문체크 배열을 따로 쓰면 된다.
candidates.add(nc); // set을 썼으므로 그냥 nc를 무지성으로 넣어도 중복된건 알아서 제거된다.
q.add(new int[]{nr, nc}); // BFS 계속 진행
...
참고로 해당 그룹 전체 탐색만 되면 되니 BFS, DFS는 상관 없다. 그냥 아무 탐색 알고리즘을 쓰면 된다. 각 그룹에 대한 탐색이 끝났다면, candidates에 포함된 각 열 인덱스에 area를 바로바로 더해주면 된다!
for (int candidate : candidates) {
cnt[candidate] += area;
}
최종적으로 cnt 배열에서 가장 큰 숫자가 답이다.
int max = 0;
for (int i = 0; i < cnt.length; i++) {
if (cnt[i] > max) max = cnt[i];
}
return max;
코드 : github
import java.util.*;
/**
* 문제 출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
*/
class Solution {
public int solution(int[][] land) {
int r = land.length;
int c = land[0].length;
int[] cnt = new int[c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (land[i][j] == 0) continue;
Set<Integer> candidates = new HashSet<>();
Queue<int[]> q = new ArrayDeque<>();
q.add(new int[]{i, j});
int area = 1;
land[i][j] = 0;
candidates.add(j);
while (!q.isEmpty()) {
int[] cur = q.poll();
int cr = cur[0];
int cc = cur[1];
for (int a = -1; a <= 1; a++) {
for (int b = -1; b <= 1; b++) {
if (((a^b)&1)!=1) continue;
int nr = cr+a;
int nc = cc+b;
if (nr<0||nr>=r||nc<0||nc>=c||land[nr][nc]==0) continue;
area++;
land[nr][nc] = 0;
candidates.add(nc);
q.add(new int[]{nr, nc});
}
}
}
for (int candidate : candidates) {
cnt[candidate] += area;
}
}
}
int max = 0;
for (int i = 0; i < cnt.length; i++) {
if (cnt[i] > max) max = cnt[i];
}
return max;
}
}
'PS > Programmers' 카테고리의 다른 글
[자바] 프로그래머스 - 분수의 덧셈 (Lv0, Java) (0) | 2024.03.29 |
---|---|
[자바] 프로그래머스 - 수열과 구간 쿼리 2 (Lv0, Java) (0) | 2023.06.16 |
[자바] 프로그래머스 - 수열과 구간 쿼리 4 (Lv0, Java) (0) | 2023.05.10 |
[파이썬] 프로그래머스 - 과일 장수 (Lv1, Python) (0) | 2023.02.06 |
[자바] 프로그래머스 - 스킬트리 (Lv2, Java) (0) | 2023.02.03 |
댓글