그리디 알고리즘은 탐욕법으로도 알려져있다.
이 알고리즘의 특징은 "현재 상황에서 지금 당당 좋은 것만 고르는 방법"을 찾는 것이다.
해당 알고리즘은 매 순간 가장 좋아보이는 것을 선택하며, 현재의 선택이 나중에 미칠 영향에
대해서는 고려하지 않는 특징이 있다.
순간마다 하는 선택은 그 순간, 지역적으로 최적이지만, 그 선택들을 계속 수집하여 최정적인 해답을 만들었다면, 그것은 최적이라는 보장은 없다.
탐욕 알고리즘 문제를 해결하는 법
1. 선택 절차 : 현재 상태에서 최적의 해답을 선택
2. 적절성 검사 : 선택된 해가 문제의 조건을 만족하는지 검사
3. 해답 검사 : 원래의 문제가 해결 되었는지 검사 후, 해결되지 않았으면 위의 과정을 반복
위의 해결법 3가지를 연습문제를 통해 학습해보았다.
문제에서 제한을 둔 것은 N의 값은 항상 10의 배수 이다 라는 것이다. 이것은 1원과 5원이 존재하지 않다는 것을 의미한다.
동전의 최소 개수로 손님한테 제공하기 위해서는 액수가 큰 동전부터 아래 단계의 동전으로 내려오는 방식을 선택할 수 있다.
문제 해결 code
public class Charge {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
int cost = Integer.parseInt(bufferedReader.readLine());
List<Integer> coins = Arrays.asList(500, 100, 50, 10);
int count = 0;
for(int i = 0; i < coins.size(); i++){
count += (cost / coins.get(i));
cost %= coins.get(i);
}
System.out.println(count);
}
}
물건의 최종 가격을 받는 변수와, 동전의 종류를 담고 있는 리스트를 생성한다.
그 다음, 큰 액수의 화폐 단위부터 나눗셈을 진행하면서 현재의 가격에서 교환할 수 있는 동전의 개수를 구한다.
값을 구한 뒤, 다음 동전을 통해 개수를 구하기 전에, 나머지 연산을 통해 현재의 화폐 단위로 교환할 수 있는 금액을 차감한다.
반복문을 마치고 나면 최적의 동전 개수 결과가 나올 것이다.
5 8 3
2 4 5 4 6
46
해당문제는 가장 큰 수와 두 번째로 큰 수를 구하는 것부터 진행 해야한다. 리스트 정렬을 통해 가장 큰 수와 두번 째로 큰수를 구하고, 큰 수의 법칙에 따라 값을 도출 할 수 있다.
여기서 해결법이 갈릴 수 있다.
위와 같이 두가지 방법을 제시할 수 있다.
M의 조건이 작을 경우에는 무엇을 사용하던 간에 상관이 없겠지만, M의 조건이 1억이 넘어가면 시간 초과가 걸릴 수 도 있다.
때문에 계산식으로 진행 하는 것도 하나의 방법이라고 할 수 있다.
public class LawOfBigNumbers {
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 m = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
int[] numbers = new int[n];
st = new StringTokenizer(br.readLine());
int i = 0;
while(st.hasMoreTokens()){
numbers[i++] = Integer.parseInt(st.nextToken());
}
Arrays.sort(numbers);
int sum = 0;
// 1번 방식
/*for(int i = 0; i < m; i++){
if((i + 1) % k ==0){
sum += numbers[numbers.length - 2];
}else{
sum += numbers[numbers.length - 1];
}
}*/
// 2번 방식
sum += (numbers[numbers.length - 1] * k) * (m / k);
sum += numbers[numbers.length - 2] * (m % k);
System.out.println(sum);
}
}
주석으로 처리된 1번 방식은 for를 사용한 반복문을 통해 가장 큰수 카운트가 K번 이루어 질 때까지 카운트를 하다가
K 배수가 될 경우 두 번째 큰 수를 더하는 방법을 채택한 방식이다.
두 번째 방식은 계산식을 사용한 방식으로 가장 큰 수를 통해 얻을 수 있는 값과 두 번째 큰 수로 만들 수 있는 수를 계산한 것이다. 가장 큰 수의 계산 법은 1싸이클 당 K번을 더할 수 있다 했으니, (가장 큰 수 * k)를 진행한다. 이 후 M번 반복 중 몇 사이클을 돌 수 있는 지 계산을 하여 곱해주면, 가장 큰 수를 통해 얻을 수 있는 합의 값을 얻을 수 있다.
두 번째로 큰 수의 합은 M번 반복 중 가장 큰 수 덧셈 횟수의 나머지를 곱해주면 된다.
25 5
2
public class UnitBecomeOne {
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 count = 0;
while(n != 1){
if(n % k == 0){
n /= k;
}else{
n -= 1;
}
count++;
}
System.out.println(count);
}
}
while을 통해 n이 1이 아닐 때 까지 반복을 수행한다. 이 후 1의 조건과 2의 조건에 의해 연산이 수행되면 카운트를 1씩 증가 시켜 n이 1이 될 때까지 연산을 수행한다.