https://school.programmers.co.kr/learn/courses/30/lessons/12979?language=python3
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 타입
- 구간 커버링 문제: 일정 구간을 커버하기 위해 최소한의 자원을 배치해야 하는 문제.
- 그리디 알고리즘: 각 단계에서 최적의 선택을 반복적으로 수행하여 전체 최적화를 추구.
- 수학적 계산 문제: 특정 범위를 커버하는 수학적 계산을 포함.
문제 분석
- 목표:
- 주어진 길이 N과 기지국의 커버 범위 W가 있을 때, 이미 설치된 기지국(stations)을 보완하여 모든 구간을 커버할 최소 기지국 개수를 계산.
- 제약:
- 기지국은 양쪽 W만큼 커버 가능.
- 추가 기지국을 최소화해야 함.
- 입력:
- N: 총 길이.
- stations: 기존 기지국 위치 배열.
- W: 기지국의 커버 범위.
- 출력:
- 모든 구간을 커버하기 위한 최소 기지국 개수.
- 핵심 아이디어:
- 기지국 간 비어 있는 구간과 마지막 기지국 이후의 남은 구간을 각각 계산하여 추가 기지국 개수를 구함.
- 하나의 기지국이 커버할 수 있는 범위는 2 * W + 1.
문제 풀이
- 필요한 변수 정의:
- current: 현재 커버되지 않은 시작 위치 (초기값 1).
- range: 하나의 기지국이 커버할 수 있는 범위 (2 * W + 1).
- answer: 필요한 기지국 개수 누적.
- 주어진 기지국을 기준으로 구간 처리:
- 각 기지국의 커버 범위(start = station - W, end = station + W)를 계산.
- 현재 커버되지 않은 시작 위치(current)와 기지국 커버 시작 위치(start)를 비교:
- 커버되지 않은 구간이 있을 경우:
- 커버되지 않은 구간 길이(uncovered = start - current)를 계산.
- 커버하기 위한 추가 기지국 개수를 (uncovered + range - 1) / range로 계산하고 answer에 추가.
- 커버 가능할 경우:
- 아무 작업도 필요 없음.
- 커버되지 않은 구간이 있을 경우:
- current를 현재 기지국 커버 범위 끝 다음(end + 1)으로 갱신.
- 마지막 구간 처리:
- 모든 기지국이 처리된 이후, 남아 있는 커버되지 않은 구간을 확인 (current <= N).
- 남아 있는 구간이 있을 경우:
- 구간 길이(uncovered = N - current + 1)를 계산.
- 커버하기 위한 추가 기지국 개수를 (uncovered + range - 1) / range로 계산하고 answer에 추가.
- 결과 반환:
- answer에 최종 추가 기지국 개수를 반환.
> java
class Solution {
public int solution(int n, int[] stations, int w) {
int answer = 0;
int current = 1; // 현재 커버되지 않은 시작 위치
int range = 2 * w + 1; // 기지국 하나가 커버할 수 있는 범위
for (int station : stations) {
int start = station - w;
int end = station + w;
// 현재 기지국으로 커버할 수 없는 영역 처리
if (current < start) {
int uncovered = start - current; // 커버되지 않은 길이
answer += (uncovered + range - 1) / range; // 필요한 기지국 개수
}
current = end + 1; // 다음 커버되지 않은 시작 위치
}
// 마지막 기지국 이후로 남아 있는 구간 처리
if (current <= n) {
int uncovered = n - current + 1;
answer += (uncovered + range - 1) / range;
}
return answer;
}
}
> python
def solution(n, stations, w):
answer = 0
current = 1
_range = w * 2 + 1
for stat in stations :
start = stat - w
end = stat + w
if current < start :
uncovered = start - current
answer += int((uncovered + _range - 1) / _range)
current = end + 1
if current <= n :
uncovered = n - current + 1
answer += int((uncovered + _range - 1) / _range)
return answer
코드 분석
if (current < start) {
int uncovered = start - current; // 커버되지 않은 길이 계산
answer += (uncovered + range - 1) / range; // 필요한 기지국 개수 계산
}
1. current < start 확인
- **현재 커버되지 않은 시작 위치 (current)**가 **기지국이 커버할 수 있는 범위의 시작점 (start)**보다 작을 때 실행됩니다.
- 이 조건은 "기지국 이전에 커버되지 않은 구간이 존재한다"는 뜻입니다.
2. 커버되지 않은 길이 계산
int uncovered = start - current;
- uncovered는 커버되지 않은 구간의 길이입니다.
- start - current는 커버되지 않은 구간의 시작부터 끝까지의 길이를 계산합니다.
3. 필요한 기지국 개수 계산
answer += (uncovered + range - 1) / range;
- (uncovered + range - 1) / range는 커버되지 않은 구간을 모두 커버하기 위해 필요한 기지국의 개수를 계산합니다.
- 계산 원리:
- range는 하나의 기지국이 커버할 수 있는 범위의 길이입니다.
- (uncovered + range - 1) / range는 "uncovered 길이를 range로 나누어 올림"의 역할을 합니다.
- + range - 1: 나머지가 있을 경우 올림 효과를 주기 위해 추가된 부분입니다.
- 예) uncovered = 4, range = 3인 경우:
- (4 + 3 - 1) / 3 = 6 / 3 = 2 (기지국 2개 필요)
예시를 통한 이해
예시 1: current = 1, start = 4, w = 1
- 주어진 값:
- range = 2 * w + 1 = 3
- uncovered = start - current = 4 - 1 = 3
- 계산:
answer += (uncovered + range - 1) / range;
answer += (3 + 3 - 1) / 3;
answer += 5 / 3;
answer += 1; // 기지국 1개 필요
예시 2: current = 1, start = 7, w = 2
- 주어진 값:
- range = 2 * w + 1 = 5
- uncovered = start - current = 7 - 1 = 6
- 계산:
answer += (uncovered + range - 1) / range;
answer += (6 + 5 - 1) / 5;
answer += 10 / 5;
answer += 2; // 기지국 2개 필요
예시 3: current = 6, start = 10, w = 1
- 주어진 값:
- range = 2 * w + 1 = 3
- uncovered = start - current = 10 - 6 = 4
- 계산:
answer += (uncovered + range - 1) / range;
answer += (4 + 3 - 1) / 3;
answer += 6 / 3;
answer += 2; // 기지국 2개 필요
최종 정리
- if (current < start): 커버되지 않은 구간이 있을 경우, 해당 구간의 길이를 계산.
- uncovered: 커버되지 않은 길이.
- (uncovered + range - 1) / range: 필요 기지국 개수를 올림하여 계산.
- answer += ...: 기지국 개수를 누적.
코드 분석
if (current <= n) {
int uncovered = n - current + 1;
answer += (uncovered + range - 1) / range;
}
주요 변수
- current: 현재 커버되지 않은 시작 위치.
- n: 총 길이 (구간의 끝 위치).
- uncovered: n - current + 1로 계산되며, 남아 있는 커버되지 않은 구간의 길이를 나타냄.
- range: 하나의 기지국이 커버할 수 있는 범위의 길이 (2 * w + 1).
- answer: 필요한 기지국 개수를 누적.
코드의 동작
- if (current <= n):
- 현재 커버되지 않은 위치(current)가 전체 길이(n) 이하라면, 남아 있는 커버되지 않은 구간이 있다는 뜻입니다.
- 예를 들어:
- current = 12, n = 16일 경우, 남아 있는 구간은 [12, 16]입니다.
- 남아 있는 구간 길이 계산:
int uncovered = n - current + 1;
- n - current + 1은 마지막 구간의 길이를 계산합니다.
- 예를 들어:
- current = 12, n = 16인 경우, uncovered = 16 - 12 + 1 = 5.
필요한 기지국 개수 계산:
answer += (uncovered + range - 1) / range;
-
- (uncovered + range - 1) / range는 커버되지 않은 길이를 하나의 기지국 범위(range)로 나누어 올림한 값을 계산합니다.
- 계산 방식은 이전 로직과 동일하며, **올림 효과를 주기 위해 + range - 1**을 더합니다.
- 결과 누적:
- 계산된 기지국 개수를 answer에 누적합니다.
예시를 통한 이해
예시 1: n = 16, current = 12, w = 2
- 주어진 값:
- range = 2 * w + 1 = 5
- uncovered = n - current + 1 = 16 - 12 + 1 = 5
- 계산:
answer += (uncovered + range - 1) / range;
answer += (5 + 5 - 1) / 5;
answer += 9 / 5;
answer += 1; // 기지국 1개 필요
예시 2: n = 20, current = 15, w = 1
- 주어진 값:
- range = 2 * w + 1 = 3
- uncovered = n - current + 1 = 20 - 15 + 1 = 6
- 계산:
answer += (uncovered + range - 1) / range;
answer += (6 + 3 - 1) / 3;
answer += 8 / 3;
answer += 2; // 기지국 2개 필요
예시 3: n = 10, current = 11, w = 1
- 주어진 값:
- current = 11이고 n = 10이므로 current > n.
- 결과:
- if (current <= n) 조건이 거짓이므로 이 로직은 실행되지 않습니다.
'TIL' 카테고리의 다른 글
[코테연습] 징검다리 건너기 (0) | 2025.01.29 |
---|---|
[코테연습] 가장 긴 팰린드롬 (1) | 2025.01.28 |
[코테연습] [PCCP 기출문제] 3번 / 아날로그 시계 (0) | 2025.01.27 |
[코테연습] 팰린드롬 만들기 (0) | 2025.01.20 |
[코테연습] 연구 분배하기 (0) | 2025.01.19 |