---
title: Baekjoon online judge. 18185.라면 사기(small)
date: 2022-03-16
tags: algorithmsolutions, 공부
excerpt: 18185.라면 사기(small) - 백준온라인
---
# 18185.라면 사기(small) - 백준온라인

해당 문제는 탐욕(greedy) 문제로 현재 수행 하는것이 최선임을 정의하여 푸는 문제입니다.

그리디도 중요하지만 예외 처리가 중요한 부분이다.

링크 :
[![image](/assets/img/algo_img/baekjoon_logo.png)](https://www.acmicpc.net/problem/18185)

---

## 18185\.라면 사기(small)

라면매니아 교준이네 집 주변에는 N개의 라면 공장이 있다. 각 공장은 1번부터 N번까지 차례대로 번호가 부여되어 있다. 교준이는 i번 공장에서 정확하게 Ai개의 라면을 구매하고자 한다(1 ≤ i ≤ N).

교준이는 아래의 세 가지 방법으로 라면을 구매할 수 있다.

i번 공장에서 라면을 하나 구매한다(1 ≤ i ≤ N). 이 경우 비용은 3원이 든다.
i번 공장과 (i+1)번 공장에서 각각 라면을 하나씩 구매한다(1 ≤ i ≤ N-1). 이 경우 비용은 5원이 든다.
i번 공장과 (i+1)번 공장, (i+2)번 공장에서 각각 라면을 하나씩 구매한다(1 ≤ i ≤ N-2). 이 경우 비용은 7원이 든다.
최소의 비용으로 라면을 구매하고자 할 때, 교준이가 필요한 금액을 출력하는 프로그램을 작성하시오.

### 입력(Input)

첫째 줄에 센서의 개수 N(1 ≤ N ≤ 10,000), 둘째 줄에 집중국의 개수 K(1 ≤ K ≤ 1000)가 주어진다. 셋째 줄에는 N개의 센서의 좌표가 한 개의 정수로 N개 주어진다. 각 좌표 사이에는 빈 칸이 하나 있으며, 좌표의 절댓값은 1,000,000 이하이다.

### 출력(Output)

첫째 줄에 문제에서 설명한 최대 K개의 집중국의 수신 가능 영역의 길이의 합의 최솟값을 출력한다.

---

### 1\. 문제 풀이
그리디 알고리즘을 이용하는 문제인데, 구매 가능한 행동이 3가지이다. <br>
그리고, i 번째 공장 i + 1 번째 공장, i + 2 번째 공장의 라면 개수에 따라서 구매 방식을 다르게 접근해야 한다. <br>

하나의 공장에서 3원으로 구매하는것 보다 두 개의 공장에서 5원으로 구매하는것이, <br>
세 개의 공장에서 7원으로 구매하는것이 효율적이라는것은 누구나 알 수 있다. <br>

그래서 처음에는 현 위치 i에서 i + 1 번째와 i + 2 번째 공장과의 살 수 있는 최대한으로 묶어서 구매하는 방식으로 문제를 풀어 봤다.

 - 3개씩 묶어서 구매
> 1 2 3 <br>
> 최소값인 1개씩 구매하여 <br>
> 0 1 2 <br>
> 을 만들면, 현 위치에서 구매 한 금액은 최소 값 1 * 7 = 7원 <br>

 - 2개씩 묶어서 구매
> 4 2 0 3 <br>
> 최소 값인 2개씩 구매하여 <br>
> 2 0 0 3 <br>
> 0 0 0 3 <br>
> 2 * 5 + 2 * 3 = 16원


그러나 위의 방식대로 접근하니 더 효율적으로 구매하지 못하는 예외 경우가 있었다. <br>
바로 i + 1 번째가 i + 2 번째보다 큰 경우인데, 아래를 살펴보면

> 2 3 2 1 <br>
> 인근 최소값인 2개씩 구매하여 <br>
> 0 1 0 1 <br>
> 0 0 0 1 <br>
> 0 0 0 0 <br>
> (2 * 7) + (1 * 3) + (1 * 3) = 20원 <br>

위와 같이 20원이 나오지만, 아래와 같이 앞의 2개씩 묶어서 뒤의 수와 일치 시켜주면
> 2 3 2 1 <br>
> 1 2 2 1 <br>
> 0 2 2 1 <br>
> 0 1 1 1 <br>
> 0 0 0 0 <br>
> (1 * 5) + (1 * 3) + (1 * 5) + (1 * 7) = 19원

19원으로 더 싸게 구매가 가능한 것이다. <br>

이는 i + 1 번째 값이 i + 2 번째 값보다 클 경우인데, 이 때에는 i 번째의 값과 [i + 1] - [i + 2] 의 값의 최소값 만큼 앞의 두개를 묶어서 사면 다음 구매에 더 싸게 구매가 가능하게 된다.

따라서 아래의 두 가지 방식으로 분기하여 그리디 방식으로 최대한 이익을 내서 구매를 한다면,

1. [i + 1] 공장의 라면 > [i + 2] 공장의 라면 <br>
    - [i], [i + 1] - [i + 2] 중의 최소값으로 선 구매 (2묶음) <br>
    - [i], [i + 1], [i + 2] 중의 최소값으로 구매 (3묶음) <br>
2. [i + 1] 공장의 라면 < [i + 2] 공장의 라면 <br>
    - [i], [i + 1], [i + 2] 중의 최소값으로 선 구매 (3묶음) <br>
    - [i], [i + 1] 중의 최소값으로 구매 (2묶음) <br>

    + [i] 의 남은 개수 구매

가장 최소의 금액으로 구매 할 수 있는 금액이 나오게 된다.


이것을 코드로 표현하겠습니다.

---

```java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Ramyeon_18185 {
    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 factory[] = new int[N + 2];

        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < N; i++) {
            factory[i] = Integer.parseInt(st.nextToken());
        }

        int answer = 0;
        for(int i = 0; i < N; i++) {
            if(factory[i] > 0) {
                // i + 1, i + 2 번 가게의 라면 유무를 확인
                // 현재 살 수 있는 가장 많은 라면을 산다.
                int min = 0;

                if(factory[i + 1] > factory[i + 2]) {
                    // i + 1의 수가 i + 2의 수보다 크면,
                    // 맨 앞의 두개를 묶어서 먼저 사고, 세 개를 묶어서 사는게 싸다.
                    // 이 때, [i] > [i+1] - [i+2] 의 값을 비교하여 최소값으로 구매
                    min = Math.min(factory[i], factory[i + 1] - factory[i + 2]);
                    answer += min * 5;
                    factory[i] -= min;
                    factory[i + 1] -= min;

                    min = Math.min(factory[i], Math.min(factory[i + 1], factory[i + 2]));
                    answer += min * 7;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                    factory[i + 2] -= min;
                } else {    // 반대는 세개 묶어 사고, 두개 묶어 사는게 싸다.
                    min = Math.min(factory[i], Math.min(factory[i + 1], factory[i + 2]));
                    answer += min * 7;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                    factory[i + 2] -= min;

                    min = Math.min(factory[i], factory[i + 1]);
                    answer += min * 5;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                }
                answer += factory[i] * 3;
                factory[i] = 0;
            }
        }

        System.out.println(answer);
    }
}

```
