본문 바로가기

CodingTest

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

https://school.programmers.co.kr/learn/courses/30/lessons/250136

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제 개요

 

각 열에서 얻을 수 있는 석유 양의 총합 중, 최댓값을 구하는 문제이다.

 

 

알고리즘

 

풀기 위해선 단계를 나눠서 접근하면 좋다.

 

 

1) 한 석유 덩어리에서 얻을 수 있는 석유 양 oil 을 구한다

 

2) 석유 덩어리가 어느 열 사이에 걸쳐있는 지 파악한다

 

3) 2)에서 구한 열에서 뽑을 수 있는 석유 양에 oil을 더한다

 

4) 1~3의 과정을 모든 석유 덩어리에 대해 반복, 결과를 list에 저장

 

5) 4)에서 완성한 list 속 최댓값을 반환한다.

 

 

풀이 

1. 석유 덩어리에서 얻을 수 있는 석유 양 구하기

from collections import deque


def calculate_oil(land, i, j, visited, oil_amount):
    # oil_amount: 열 당 얻을 수 있는 석유의 총량
    # visited: 방문여부 확인
    
    oil = 0                          # 현재 석유덩어리에서 얻을 수 있는 석유량
    n, m = len(land), len(land[0])   # land의 행, 열 수 
    que = deque()                    # BFS 탐색에 필요
    que.append([i, j])               # 시작점을 deque에 넣기
    
    dx = [0, -1, 0, 1]
    dy = [-1, 0, 1, 0]
    
    l, r = j, j     # 현재 보는 석유 덩어리가 걸쳐있는 열
                   # l: 좌측 경계선
                   # r: 우측 경계선
    
    # 1) 석유량 산출
    # 2) 석유 덩어리가 있는 열 구하기
    while que:     # BFS 탐색
        x, y = que.popleft()
        
        if land[x][y] == 1 and visited[x][y] == False:  # 석유가 있고, 방문하지 않은 경우
            visited[x][y] = True   # 방문 처리
            oil += 1               # 석유량 증가
            
            l = min(l, y)    # l 갱신
            r = max(r, y)    # r 갱신
            
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if (0 <= nx and nx < n) and (0 <= ny and ny < m):       # 영역을 벗어나지 않음
                    if land[nx][ny] == 1 and visited[nx][ny] == False:  # 석유가 있고, 방문하지 않은 경우
                        que.append([nx, ny])   
                    else:          # 그 외
                        continue   # 무시
    
    # 3) oil_amount 에서, 지금 본 석유덩어리가 걸쳐있는 열들에 oil 만큼 더하기
    for i in range(l, r+1):     # 열 구간 [l, r] 사이에서는 oil 만큼 석유를 더 얻을 수 있음
        oil_amount[i] += oil    # oil 만큼 석유량 증가
        
    return [oil, l, r]

 

BFS를 사용하여 한 석유 덩어리에서 얻을 수 있는 석유의 양을 구한다.

이 과정에서 석유 덩어리가 어느 열 사이에 걸쳐있는 지 파악한다. 

 

 

마지막으로, 현재 보고있는 석유 덩어리가 가로지르는 열에서 얻을 수 있는 석유 총량에, 앞서 구한 석유량 "oil"을 더해줘야 한다.

 

2.  열 당 얻을 수 있는 석유 총량 구하기

def solution(land):
    visit_map = [[False for _ in range(len(land[0]))] for _ in range(len(land))]  # 방문여부 저장
    n, m = len(land), len(land[0])
    oil_amount = [0 for _ in range(m)]   # 각 열에서 얻을 수 있는 석유 총량
    
    for i in range(n):
        for j in range(m):
            if land[i][j] == 1 and visit_map[i][j] == False:        # 석유가 묻혀있고, 방문한 적이 없다면
                calculate_oil(land, i, j, visit_map, oil_amount)    # 석유량 구해서, 가로지르는 열 구간에 그만큼 더하기

 

주어진 "land"를 탐색하며, 방문한 적이 없지만 석유가 있는 칸에 대해서만 석유량을 구하는 등의 작업을 수행한다.

 

3. 최댓값 구하기

    ans = max(oil_amount)   # 열별 얻을 수 있는 석유 총량 중 최댓값
    return ans

 

열 별로 얻을 수 있는 석유량 중 최댓값을 반환한다.

 

 

전체 코드

# 참고한 글: https://velog.io/@seungjae/프로그래머스-PCCP-기출문제-2번-석유-시추-Python-BFS
from collections import deque


def calculate_oil(land, i, j, visited, oil_amount):
    # oil_amount: 열 당 얻을 수 있는 석유의 총량
    # visited: 방문여부 확인
    
    oil = 0                          # 현재 석유덩어리에서 얻을 수 있는 석유량
    n, m = len(land), len(land[0])   # land의 행, 열 수 
    que = deque()                    # BFS 탐색에 필요
    que.append([i, j])               # 시작점을 deque에 넣기
    
    dx = [0, -1, 0, 1]
    dy = [-1, 0, 1, 0]
    
    l, r = j, j     # 현재 보는 석유 덩어리가 걸쳐있는 열
                   # l: 좌측 경계선
                   # r: 우측 경계선
    
    # 1) 석유량 산출
    # 2) 석유 덩어리가 있는 열 구하기
    while que:     # BFS 탐색
        x, y = que.popleft()
        
        if land[x][y] == 1 and visited[x][y] == False:  # 석유가 있고, 방문하지 않은 경우
            visited[x][y] = True   # 방문 처리
            oil += 1               # 석유량 증가
            
            l = min(l, y)    # l 갱신
            r = max(r, y)    # r 갱신
            
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if (0 <= nx and nx < n) and (0 <= ny and ny < m):       # 영역을 벗어나지 않음
                    if land[nx][ny] == 1 and visited[nx][ny] == False:  # 석유가 있고, 방문하지 않은 경우
                        que.append([nx, ny])   
                    else:          # 그 외
                        continue   # 무시
    
    # 3) oil_amount 에서, 지금 본 석유덩어리가 걸쳐있는 열들에 oil 만큼 더하기
    for i in range(l, r+1):     # 열 구간 [l, r] 사이에서는 oil 만큼 석유를 더 얻을 수 있음
        oil_amount[i] += oil    # oil 만큼 석유량 증가
        
    return [oil, l, r]


def solution(land):
    visit_map = [[False for _ in range(len(land[0]))] for _ in range(len(land))]  # 방문여부 저장
    n, m = len(land), len(land[0])
    oil_amount = [0 for _ in range(m)]   # 각 열에서 얻을 수 있는 석유 총량
    
    for i in range(n):
        for j in range(m):
            if land[i][j] == 1 and visit_map[i][j] == False:        # 석유가 묻혀있고, 방문한 적이 없다면
                calculate_oil(land, i, j, visit_map, oil_amount)    # 석유량 구해서, 가로지르는 열 구간에 그만큼 더하기
    
    ans = max(oil_amount)   # 열별 얻을 수 있는 석유 총량 중 최댓값
    return ans

 

 

실행 결과

'CodingTest' 카테고리의 다른 글

연속된 부분 수열의 합  (1) 2024.03.27
이웃한 칸  (1) 2024.03.21
과제 진행하기  (0) 2024.03.16
[PCCP 기출문제] 1번 / 붕대 감기  (0) 2024.03.04
[PCCE 모의고사] 10번 문제풀이  (0) 2024.02.19