Algorithm

[Algorithm] 떡볶이 떡 만들기

씬프 2021. 5. 17. 09:00
반응형

문제

오늘 동빈이는 여행가신 부모님을 대신해서 떡집 일을 하기로 했다. 오늘은 떡볶이 떡을 만드는 날이다. 동빈이네 떡볶이떡은 재밌게도 떡볶이 떡의 길이가 일정하지 않다. 대신에 한 봉지 안에 들어가는 떡의 총 길이는 절단기로 잘라서 맞춰준다. 

절단기에 높이 H를 지정하면 줄지어진 떡을 한번에 절단한다. 높이가 H보다 긴 떡은 H 위의 부분이 잘릴 것이고, 낮은 떡은 잘리지 않는다.

예를 들어 높이가 19, 14, 10, 17cm인 떡이 나란히 있고 절단기 높이가 15cm로 지정하면 자른 뒤 떡의 높이는 15, 14, 10, 15cm가 될 것이다. 잘린 떡의 길이는 차례대로 4, 0, 0, 2cm이다. 손님은 6cm만큼의 길이를 가져간다.

손님이 왔을 때 요청한 총 길이가 M일 때, 적어도 M만큼의 떡을 얻기 위해 절단기에 설정할 수 있는 높이의 최대값을 구하는 프로그램을 작성하시오.

 

입력 조건

첫째 줄에 떡의 개수 N과 요청한 떡의 길이 M이 입력된다.

둘째 줄에 떡의 개별 높이가 주어진다.

 

출력 조건

적어도 M만큼의 떡을 집에 가져갈 수 있는 절단기의 높이 H를 출력한다.

 

풀이

가장 긴 떡의 길이를 절단기 높이로 두고, 줄여가면서 남는 떡의 길이를 M과 비교한다.

import java.util.*;

class Main {

  public static void main(String[] args) {
    
    int n, m;
    Scanner sc = new Scanner(System.in);
    n = sc.nextInt();
    m = sc.nextInt();
    int[] dduks = new int[n];
    for (int i = 0; i < n; i++)
      dduks[i] = sc.nextInt();
    sc.close();

    Arrays.sort(dduks);
    int h = dduks[n-1];
    while (true) {
      int sum = 0;
      for (int d : dduks) {
        if (d >= h) {
          sum += (d - h);
        }
      }
      if (sum == m) {
        break;
      }
      h--;
    } // end while

    System.out.println(h);

  } // end main
}

 

다른 풀이 (in 이것이 코딩테스트다 github)

        // 이진 탐색을 위한 시작점과 끝점 설정
        int start = 0;
        int end = (int) 1e9;
        // 이진 탐색 수행 (반복적)
        int result = 0; 
        while (start <= end) {
            long total = 0;
            int mid = (start + end) / 2;
            for (int i = 0; i < n; i++) {
                // 잘랐을 때의 떡의 양 계산
                if (arr[i] > mid) total += arr[i] - mid; 
            }
            if (total < m) { // 떡의 양이 부족한 경우 더 많이 자르기(왼쪽 부분 탐색)
                end = mid - 1;
            }
            else { // 떡의 양이 충분한 경우 덜 자르기(오른쪽 부분 탐색)
                result = mid; // 최대한 덜 잘랐을 때가 정답이므로, 여기에서 result에 기록 
                start = mid + 1;
            }
        }

배열에 대해서 이진 탐색을 시도한다. 시작점과 끝점을 설정한다.

start가 end(1e9 == 1 * 10^9, 아주 큰 수)보다 작거나 같을 때 반복적으로 수행한다.

start와 end의 중간 점을 mid에 저장한다. 떡의 길이가 저장된 배열을 탐색하는데,

mid보다 큰 길이를 가진 떡에 대해서만 잘라낸 나머지 값을 total에 더한다.

 

total이 M보다 작은 경우는 떡의 길이가 부족한 것이기 때문에, end에 mid-1을 저장하고 다시 시도한다.

 

total이 M보다 큰 경우는 떡의 길이가 충분하기 때문에 결과에 mid를 저장하고, start = mid+1로 절단기 높이를 높인다. 만약 정확한 높이를 찾았다면 start > end로 종료되면서 result를 높이 H로 반환하면 된다.

아닌 경우 start와 end 사이에서 다시 탐색을 진행한다.

 

결과

처음 풀었던대로 푼다면, 만약 떡의 길이가 아주 긴 떡이 있고 계속 줄여와야 한다면 엄청난 비효율을 가질 수 밖에 없다. 이진탐색 알고리즘을 사용한다면 중간 값으로 도약하면서 줄여가기 때문에 비효율에 대비할 수 있다.

'Algorithm' 카테고리의 다른 글

[Algorithm] 개미 전사  (0) 2021.05.19
[Algorithm] 1로 만들기  (0) 2021.05.18
[Algorithm] 부품 찾기  (0) 2021.05.16
[Algorithm] 두 배열의 원소 교체  (0) 2021.05.15
[Algorithm] 성적이 낮은 순서대로 출력하기  (0) 2021.05.14