반응형
Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- localtime
- SQL Mapper
- Comparable
- 자바의 정석
- spring security
- 멀티태스킹
- Comparator
- 분할정복
- 분할정복 알고리즘
- 티스토리챌린지
- hackerrank
- spring security 설정
- over()
- 멀티프로세싱
- BFS
- 리눅스
- 자바의정석
- LocalDate
- 혼공얄코
- Arrays
- 백트래킹
- 프로그래머스
- 둘만의 암호
- 둘만의 암호 자바
- 오블완
- 오버로딩
- 오버라이딩
- java
- 프로그래머스 둘만의 암호
- greedy
Archives
- Today
- Total
쉽게 쉽게
[알고리즘] 그리디(Greedy)란? (백준 11047, 13305) 본문
반응형
📌 핵심 요약
- 그리디 알고리즘 — 매 순간 지금 당장 가장 좋아 보이는 선택을 반복해 최적해를 구하는 방법
- 성립 조건 — 탐욕적 선택 속성 + 최적 부분 구조가 모두 만족해야 적용 가능
- 주의점 — 그리디가 항상 정답은 아님. "왜 이 선택이 최적인가"를 반드시 증명해야 함
1 그리디 알고리즘이란?
그리디(Greedy) 알고리즘은 "지금 이 순간 가장 좋아 보이는 선택"을 반복하여 최적해를 구하는 방식이다. 미래를 고려하지 않고 현재 상태에서 가장 이득이 되는 선택만을 계속하다 보면 전체 최적해에 도달할 수 있는 문제에 적용한다.
한 줄 정의
각 단계에서 최선인 선택을 반복했을 때 전역적으로도 최선인 결과가 나오는 알고리즘핵심 성립 조건
그리디를 적용하려면 반드시 아래 두 조건이 모두 성립해야 한다.
| 조건 | 설명 | 확인법 |
|---|---|---|
| 탐욕적 선택 속성 | 지금 최선의 선택이 나중에도 최선임이 보장됨 | 교환 논증 |
| 최적 부분 구조 | 전체 최적해가 부분 최적해들로 구성됨 | 귀납적 증명 |
교환 논증(Exchange Argument)이란?
최적해에서 그리디가 선택한 것과 다른 선택이 있다면, 그것을 그리디의 선택으로 교환해도 결과가 나빠지지 않음을 보이는 증명 방법이다. "바꿔도 손해가 없다 → 그리디 선택이 항상 안전하다"는 논리 구조다.그리디 vs DP
| 구분 | 그리디 | DP (동적 프로그래밍) |
|---|---|---|
| 선택 방식 | 현재 최선만 선택 | 모든 경우를 고려 |
| 속도 | 빠름 | 상대적으로 느림 |
| 적용 범위 | 조건 만족 시만 | 더 넓음 |
| 구현 난이도 | 단순 | 복잡 |
| 대표 예시 | 동전 거스름돈, 회의실 배정 | 배낭 문제, 최장 공통 부분 수열 |
그리디가 통하지 않는 경우
동전이 1, 3, 4원이고 목표가 6원일 때 — 그리디는 4+1+1=3개를 선택하지만 최적은 3+3=2개다. 동전 단위가 배수 관계가 아닐 때는 그리디가 틀릴 수 있으며, 이때는 DP를 써야 한다.2 BOJ 11047 — 동전 0
BOJ #11047
동전 0
N종류의 동전으로 합이 K가 되도록 만들 때 필요한 동전 개수의 최솟값을 구하라. 각 동전의 가치는 오름차순이며, i ≥ 2인 경우 Ai는 Ai-1의 배수다.
풀이 아이디어
핵심 조건은 "각 동전은 바로 아래 동전의 배수"라는 점이다. 이 조건 덕분에 큰 동전을 쪼개면 정확히 작은 동전들로 대체되므로, 가장 큰 동전부터 최대한 많이 사용하는 전략이 항상 최적이다.
그리디 정당성
큰 동전 1개 = 작은 동전 여러 개이므로, 큰 동전을 먼저 쓸수록 총 개수가 줄어든다. 배수 조건이 없는 동전 문제라면 그리디가 틀릴 수 있으니 주의!예제 추적 — K = 4200 / 동전: 1 5 10 50 100 500 1000 5000 10000 50000
| 단계 | 동전 | 사용 개수 | 남은 K |
|---|---|---|---|
| 1 | 1000원 | 4개 | 200 |
| 2 | 100원 | 2개 | 0 |
| 합계 | 6개 ✅ | - | |
풀이 과정
- 동전 배열을 입력받는다 (이미 오름차순으로 주어짐)
- 가장 큰 동전(인덱스 n-1)부터 역순으로 순회한다
- 현재 동전으로 K를 나눈 몫만큼 count에 더하고, K를 그만큼 차감한다
- K가 0이 되면 종료, count를 출력한다
Java 코드
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// N과 K를 첫 줄에서 같이 읽음
String[] firstLine = br.readLine().trim().split(" ");
int n = Integer.parseInt(firstLine[0]);
int k = Integer.parseInt(firstLine[1]);
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(br.readLine().trim());
}
int count = 0;
// 큰 동전부터 탐욕적으로 사용
for (int i = arr.length - 1; i >= 0; i--) {
int mod = k / arr[i]; // 이 동전을 몇 개 쓸 수 있나
count += mod;
k -= arr[i] * mod; // 남은 금액 갱신
if (k == 0) break;
}
System.out.print(count);
}
}
3 BOJ 13305 — 주유소
BOJ #13305
주유소
일직선으로 N개의 도시가 있고 각 도시에 주유소가 있다. 제일 왼쪽 도시에서 오른쪽 끝 도시까지 이동할 때 드는 최소 주유 비용을 구하라. 기름통 크기는 무제한이며 1km당 1리터를 소모한다.
풀이 아이디어
각 구간을 지나갈 때 "지금까지 만난 주유소 중 가장 싼 가격"으로 기름을 채우는 것이 항상 최적이다. 더 싼 주유소를 만나는 순간 그 가격이 새로운 기준이 되고, 이후 구간은 모두 이 가격으로 계산한다.
핵심 그리디 관찰
각 구간마다 지금까지 본 최솟값(minPrice) × 거리를 더해나가면 된다. minPrice보다 싼 주유소가 나오면 그 순간부터 minPrice를 갱신한다.예제 추적 — 가격: 5 2 4 1 / 거리: 2 3 1
| 구간 | 현재 가격 | minPrice | 구간 비용 | 누적 |
|---|---|---|---|---|
| 0 → 1 (2km) | 5 | 5 | 5×2 = 10 | 10 |
| 1 → 2 (3km) | 2 | 2 | 2×3 = 6 | 16 |
| 2 → 3 (1km) | 4 | 2 | 2×1 = 2 | 18 ✅ |
자료형 주의 — int가 아닌 long!
거리 최대 10억 × 가격 최대 10억 = 최대 10¹⁸ → int 범위(약 21억)를 훨씬 초과한다. dist, price, result 모두 반드시 long으로 선언해야 한다.풀이 과정
- 거리 배열(N-1개)과 가격 배열(N개)을 각각 한 줄씩 입력받는다
- minPrice를 첫 번째 도시 가격으로 초기화한다
- i = 0부터 N-2까지 순회하며 minPrice를 갱신하고, minPrice × dist[i]를 result에 누적한다
- result를 출력한다 (자료형은 반드시 long)
Java 코드
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
// 거리 입력 (N-1개, 한 줄)
StringTokenizer st = new StringTokenizer(br.readLine());
long[] dis = new long[n - 1];
for (int i = 0; i < n - 1; i++) {
dis[i] = Long.parseLong(st.nextToken());
}
// 가격 입력 (N개, 한 줄)
st = new StringTokenizer(br.readLine());
long[] oil = new long[n];
for (int i = 0; i < n; i++) {
oil[i] = Long.parseLong(st.nextToken());
}
// 그리디: 지금까지 본 최솟값으로 각 구간 채우기
long result = 0;
long minPrice = oil[0];
for (int i = 0; i < n - 1; i++) {
minPrice = Math.min(minPrice, oil[i]); // 최솟값 갱신
result += minPrice * dis[i]; // 이 구간 비용 누적
}
System.out.print(result);
}
}
| 잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다. |

반응형
'알고리즘 > 그리디 (Greedy)' 카테고리의 다른 글
| [백준] 그리디 문제 풀이 (백준 1931, 11399, 1541) (0) | 2026.04.13 |
|---|