코딩 테스트/그리디

백준 3213 - 피자 (자바 - 그리디)

방구석 대학생 2023. 5. 13. 20:44

https://www.acmicpc.net/problem/3213

 

3213번: 피자

첫째 줄에 친구의 수 N이 주어진다. (1 ≤ N ≤ 10,000) 다음 N개 줄에는 각 친구가 먹을 수 있는 피자의 양이 주어진다. 이 값은 항상 분수이며, 1/4, 1/2, 3/4중 하나이다.

www.acmicpc.net

 

* 문제 요약

상근이는 생일을 기념해 친구들과 피자를 먹으러갔다.

친구들은 매우 어려서 피자 한 판을 먹을 수 없다. 하지만 각 친구들은 자신이 먹을 수 있는 피자의 양을 알고 있다.

친구들이 먹을 수 있는 피자의 양은 항상 1/4, 1/2, 3/4 중 하나이다.

피자 최소 몇 판을 시키면 친구들이 모두 피자를 자신이 먹을 수 있는 양만큼 먹을 수 있는지 구하는 프로그램을 작성하시오.

상근이는 피자를 먹지 않으며, 모든 친구들이 정확히 한 조각씩 피자를 가져야 한다.

 

* 입력

첫째 줄에 친구의 수 N 이 주어진다. (1 <= N <= 10,000) 

다음 N 개의 줄에는 각 친구가 먹을 수 있는 피자의 양이 주어진다. 이 값은 항상 분수이며, 1/4, 1/2, 3/4 중 하나이다.

 

* 출력

피자를 최소 몇 판 시키면 모든 친구들이 자신이 먹을 수 있는 양만큼 먹는지 출력한다.

 

* 예시

 

* 해결 과정

매 반복마다 먹을 수 있는 만큼의 피자를 먹고 난 후 남은 피자들은 모두 버려야 하는지 다시 쓸 수 있는지 감을 잘 못잡아서 많이 애먹었던 문제다.

 

피자 한 판을 100 이라고 설정하고 친구들이 먹을 수 있는 양 1/4, 1/2, 3/4 를 각각 25, 50, 75 로 설정해서 피자 배열에 저장했다.

이 배열을 내림차순 정렬해준 다음 반복문으로 순차탐색을 하면서 현재 탐색중인 친구가 주문이 나와있는 피자 한판을 기준으로 얼마나 먹을 수 있는지 판별한다.

 

친구가 먹을 수 있는 크기가 현재 나와있는 피자 크기보다 작다면 먹을 수 있는 것으로 판단하고, 현재 나와있는 피자의 크기를 친구가 먹을 수 있는 크기만큼 줄인다.

만약 친구가 먹을 수 있는 크기 보다 현재 나와있는 피자 크기가 작은 경우, 현재 나와있는 피자는 여분의 피자로 남겨둔 다음, 앞전에 나온 여분의 피자 중에서 현재 친구가 먹을 수 있는 크기의 피자가 있는지 찾아본다.

만약 여분의 피자 중 현재 친구가 먹을 수 있는 크기의 피자가 있는 경우 해당 피자를 여분의 피자 리스트에서 삭제해준다.

(더 정확하게 하자면 크기를 비교해서 여분의 피자 크기가 친구가 먹을 수 있는 피자의 크기보다 더 큰 경우 리스트에서 삭제하지 않고 크기만 줄여서 다시 리스트에 넣어줘야 하는데, 일단 리스트에서 삭제하기만 해도 통과를 받기에는 문제가 없는 것이 확인되었다.)

 

만약 여분의 피자 중에서도 현재 친구가 먹을 수 있는 크기의 피자가 없는 경우 새로 피자를 한 판 시켜서 (피자 값을 100 으로 초기화) 현재 친구에게 피자를 먹여주고, 주문 시킨 피자의 갯수를 늘려준다.

 

위의 과정을 모든 친구들이 피자를 먹을 수 있을 때까지 반복한다.

 

* 코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) throws NumberFormatException, IOException {
        new Main().solution();
    }

    private void solution() throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        
        int count = Integer.parseInt(br.readLine());
        Integer [] pizza = new Integer[count];
        int result = 100;
        int pizzaCount = 1;
        for(int i = 0; i < count; i++){
            String str = br.readLine();

            if(str.equals("1/4")){
                pizza[i] = 25;
            }
            else if(str.equals("1/2")){
                pizza[i] = 50;
            }
            else if(str.equals("3/4")){
                pizza[i] = 75;
            }
        }

        Arrays.sort(pizza, Collections.reverseOrder());
        List<Integer> spare = new ArrayList<>();
        for(int i = 0; i < count; i++){
            if(result >= pizza[i]){
                result -= pizza[i];
            }
            else{
                spare.add(result);
               
                int index = i;
                if(spare.stream().filter(x -> x >= pizza[index]).count() > 0){
                    for(int j = 0; j < spare.size(); j++){
                        if(spare.get(j) >= pizza[index]){
                            spare.remove(j);
                            break;
                        }
                    }
                }
                else{
                    pizzaCount++;
                    result = 100 - pizza[i];
                }
            }
        }

        bw.write(pizzaCount + "\n");
        bw.flush();
        bw.close();
        br.close();
    }
}

 

피자 주문량을 최소화 하기 위해 먹을 수 있는 피자의 크기를 기준으로 배열을 내림차순 정렬 한 점, 

그리고 주문 시킨 후 남아있는 피자 중 먹을 수 있는 피자가 있다면 추가 주문을 하지 않고 여분의 피자를 내준점에서 매 단계마다 전체를 기준으로 최적에 가까운 해를 찾기 위해 로직을 최적화 했으므로 그리디 알고리즘 문제에 해당된다.