[Coding Test] 그리디 알고리즘
흔히 탐욕 알고리즘이라고도 불리는 그리디 알고리즘은, 문제 해결을 위해 각 단계에서 최적의 선택을 하는 알고리즘 설계 방법이다.
최적의 선택을 하는 알고리즘 중 동적 계획법 보다 구현이 쉽고, 시간 복잡도가 우수하다는 장점이 있지만,항상 최적의 해를 보장하지 못한다는 단점도 있다.
그렇기 때문에 논리 유무를 충분히 확인한 후 사용해도 되는지 판단해야한다.
보통 최단 경로, 최소 신장 트리(Minimum Spanning Tree) 등에 활용할 수 있다.
핵심 이론 / 수행 과정
- 해 선택 : 현재 상태에서 가장 최선이라고 생각되는 해를 선택한다.
- 적절성 검사 : 현재 선택한 해가 전체 문제의 제약 조건에 벗어나지 않는지 검사한다.
- 해 검사 : 현재까지 선택한 해 집합이 전체 문제를 해결할 수 있는지를 검사한다. 전체 문제를 해결하지 못한다면 위의 과정을 반복한다.
그리디 알고리즘의 개념을 익히는데 자주 등장하는 “동전 개수 구하기” 의 문제를 풀며 개념을 익혀보자.
https://www.acmicpc.net/problem/11047
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
// 동전 개수
int N = Integer.parseInt(st.nextToken());
// 목표 값
int K = Integer.parseInt(st.nextToken());
// 동전 배열
int[] A = new int[N];
// 동전 값 저장하기
for(int i = 0; i<N; i++){
st = new StringTokenizer(br.readLine());
A[i] = Integer.parseInt(st.nextToken());
}
// 사용한 동전 개수
int count = 0;
// 오름차순이기에 뒤에서 부터 순회하며 기준에 맞는 큰 값을 찾는다.
for(int i = N -1; i>=0 ; i--){
//현재 동전
int coin = A[i];
// 동전의 값이 K와 같거나 작다면 적합한 동전
if(coin <= K){
count += K / coin; // 해당 동전을 사용하는 만큼 count를 더해준다.
K = K % coin; // 동전을 사용하고 나머지 금액을 넣어준다.
}
}
System.out.println(count);
}
}
그리드의 내용이 길지 않으니 핵심 알고리즘을 활용하는 문제를 하나 더 풀어보자.
https://www.acmicpc.net/problem/1541
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int answer = 0;
Scanner sc = new Scanner(System.in);
// 가장 작은 값을 구하기 위해서는 -를 기준으로 나눠서 다음 -까지의 값들을 더해준다.(일종의 괄호)
String[] given_split = sc.nextLine().split("-");
for(int i = 0; i < given_split.length; i++){
// 구분된 값들을 모두 더한다.
int tmp = mySum(given_split[i]);
// 첫 번쨰 값이라면 값을 뺴는 기준값이 된다.
if(i == 0){
answer += tmp;
}else{
answer -= tmp;
}
}
System.out.println(answer);
}
static private int mySum(String plus) {
int sum = 0;
// "+" 를 기준으로 자른다.
// split은 regex로 인식하기에 "+"만 작성하면 인식되지 않는다.
String[] plus_split = plus.split("[+]");
// 모든 값들을 괄호와 같은 개념으로 더한다.
for(int i = 0; i < plus_split.length; i++){
sum += Integer.parseInt(plus_split[i]);
}
return sum;
}
}
Ref.
Do it! 알고리즘 코딩 테스트 - 자바 편, 이지스퍼블리싱/김종관 저