[백준] 1781 컵라면 (JAVA)

2025. 10. 11. 18:46·코딩 테스트

문제 링크:

1781번: 컵라면

 

 

난이도: 골드 2

 

 

문제:

상욱 조교는 동호에게 N개의 문제를 주고서, 각각의 문제를 풀었을 때 컵라면을 몇 개 줄 것인지 제시 하였다. 하지만 동호의 찌를듯한 자신감에 소심한 상욱 조교는 각각의 문제에 대해 데드라인을 정하였다.

위와 같은 상황에서 동호가 2, 6, 3, 1, 7, 5, 4 순으로 숙제를 한다면 2, 6, 3, 7번 문제를 시간 내에 풀어 총 15개의 컵라면을 받을 수 있다.

 

문제는 동호가 받을 수 있는 최대 컵라면 수를 구하는 것이다. 위의 예에서는 15가 최대이다.

 

문제를 푸는데는 단위 시간 1이 걸리며, 각 문제의 데드라인은 N이하의 자연수이다. 또, 각 문제를 풀 때 받을 수 있는 컵라면 수와 최대로 받을 수 있는 컵라면 수는 모두 2^31보다 작은 자연수이다.

 

 

입력:

첫 줄에 숙제의 개수 N (1 ≤ N ≤ 200,000)이 들어온다. 다음 줄부터 N+1번째 줄까지 i+1번째 줄에 i번째 문제에 대한 데드라인과 풀면 받을 수 있는 컵라면 수가 공백으로 구분되어 입력된다.

 

 

출력:

첫 줄에 동호가 받을 수 있는 최대 컵라면 수를 출력한다.

 

 

문제 이해:

문제의 내용은 간단하다.

 

N개의 문제가 주어질 때, 각 문제마다 마감일(기한) 과 보상(컵라면 개수) 이 주어진다.
하루에 풀 수 있는 문제는 하나뿐이므로,
주어진 기간 안에서 가장 많은 컵라면을 얻을 수 있도록 문제를 선택해야 한다.

 

예를 들어, 예제 입력 1을 보면 다음과 같다.

  • 1일 차에는 컵라면 7개짜리 문제
  • 2일 차에는 5개짜리 문제
  • 3일 차에는 2개짜리 문제
  • 4일 차에는 6일 차의 1개짜리 문제를 푼다

즉, 7 + 5 + 2 + 1 = 15가 정답이다.

 

 

구현 방향:

이 문제는 입력 개수가 많기 때문에,
단순한 완전 탐색보다는 그리디(Greedy) + 우선순위 큐(Priority Queue) 를 사용하는 방식이 적합하다.

 

그리디 아이디어 자체는 비교적 쉽게 떠올릴 수 있지만,
이를 효율적으로 구현하기 위해 우선순위 큐를 사용하는 발상은 다소 어렵게 느껴질 수 있다.


그러나 작성자는 이전에 “순회강연” 문제를 풀면서 이 방식을 경험했기 때문에,
이번 문제에도 동일한 원리를 적용할 수 있었다.

 

전체적인 구현 흐름은 다음과 같다.

  1. 가장 마지막 날부터 1일차까지 반복한다.
  2. 각 날짜에 해당하는 모든 컵라면 보상 값을 우선순위 큐에 넣는다.
  3. 큐 안에서 가장 큰 값(보상이 가장 큰 문제) 을 선택해 pop한다.
  4. 이 과정을 1일까지 반복하면서, 선택된 값들을 모두 더한다.

이 방법을 사용하면,
각 날짜에 가능한 문제들 중 “그날 풀 수 있는 최고의 선택”만을 빠르게 고를 수 있다.

 

예시로 흐름을 들어보면 다음과 같다.

7
1 6
1 7
2 8
2 8
3 2
3 1
6 1

날짜별로 살펴보면 다음과 같다.

  • 6일차 → 큐 상태: [1] → 가장 큰 값 1 선택 → 누적: +1
  • 5일차 → 해당 문제 없음
  • 4일차 → 해당 문제 없음
  • 3일차 → 큐 상태: [2, 1] → 2 선택 → 누적: +3
  • 2일차 → 큐 상태: [8, 8, 1] → 8 선택 → 누적: +11
  • 1일차 → 큐 상태: [6, 7, 8] → 8 선택 → 누적: +19

따라서 정답은 19가 된다.

 

작성자는 각 날짜별로 문제 정보를 효율적으로 관리하기 위해
Map<Integer, List<Integer>> 형태를 사용했다.

  • key → 마감일(deadline)
  • value → 해당 날짜에 가능한 컵라면 개수 목록

 

이 구조를 사용하면,
날짜별 문제 정보를 쉽게 접근할 수 있고,
우선순위 큐를 통해 매일 가장 큰 보상만 빠르게 선택할 수 있다.

 

이를코 코드로 그대로 구현하면 다음과 같다.

 

 

정답 코드:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N;

    static Map<Integer, LinkedList<Integer>> map=new HashMap<>();
    static Queue<Integer> q= new PriorityQueue<>(Collections.reverseOrder());
    static Set<Integer> day=new TreeSet<>(); //day를 담을 set(자동 정렬)

    public static int solve(){
        int result=0;
        int max = ((TreeSet<Integer>) day).last(); //set에서 가장 큰 값 꺼내기

        //큰 deadLine부터 1일차까지 역순 탐색
        for(int i=max; i>=1; i--){
            //해당 deadLine이 기한인 컵라면 개수 Queue에 추가
            if(map.containsKey(i)){
                for(int num: map.get(i)){
                    q.add(num);
                }
            }
            //큐에 서 가장 큰값 빼면서 결과에 더하기.
            if(!q.isEmpty()) result+=q.poll();

        }
        return result;
    }

    public static void main(String[] args) throws IOException {
        //초기 세팅
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        N= Integer.parseInt(br.readLine());

        for(int i=0; i<N; i++){
            StringTokenizer st=new StringTokenizer(br.readLine());

            int deadLine=Integer.parseInt(st.nextToken());
            int remenCount=Integer.parseInt(st.nextToken());

            //map에 마감일과 라면 개수 추가
            map.putIfAbsent(deadLine,new LinkedList<>());
            map.get(deadLine).add(remenCount);

            //set에 마감일 추가
            day.add(deadLine);
        }
        //초기 세팅 끝

        //탐색 시작
        int result = solve();

        //결과 출력
        System.out.println(result);


    }
}

 

 

마무리하며:

작성자는 문제를 풀 때 겉보기에는 간단해 보여도,
시간 복잡도(Big-O)를 고려하며 최적화해야 하는 문제 유형이 가장 어렵다고 느꼈다.

 

문제를 보면, 종종 연산이 많은 방식의 해결법이 먼저 떠올라서
효율적인 접근을 떠올리는 데 시간이 오래 걸리는 것 같다.

 

DFS나 BFS 탐색 문제의 경우 풀이 방식이 비교적 정해져 있지만,
이런 그리디나 최적화 유형의 문제는
무엇을 기준으로 최적화를 해야 하는지,
어떤 자료구조를 사용해야 연산을 줄일 수 있는지를
스스로 고민해야 하기 때문에 더욱 어렵게 느껴진다.

 

따라서 앞으로는 더 많은 문제를 풀어보며
시간 복잡도에 대한 감각과 최적화 아이디어를 자연스럽게 익혀야겠다고 생각했다.

 

 

감사합니다.

'코딩 테스트' 카테고리의 다른 글

[백준] 1931 회의실 배정 (JAVA)  (0) 2025.10.14
[백준] 14469 소가 길을 건너간 이유 3 (JAVA)  (0) 2025.10.13
[백준] 9935 문자열 폭발 (JAVA)  (0) 2025.10.10
[백준] 2109 순회강연 (JAVA)  (0) 2025.10.09
[백준] 1189 컴백홈 (JAVA)  (0) 2025.10.08
'코딩 테스트' 카테고리의 다른 글
  • [백준] 1931 회의실 배정 (JAVA)
  • [백준] 14469 소가 길을 건너간 이유 3 (JAVA)
  • [백준] 9935 문자열 폭발 (JAVA)
  • [백준] 2109 순회강연 (JAVA)
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    타임리프
    fetch join
    LocalDateTime
    쿼리dsl
    스프링
    자바
    Java
    객체지향
    JPA
    스프링 데이터 JPA
    SOLID
    불변객체
    spring
    QueryDSL
    dfs
    mvc
    thymeleaf
    쿼리
    예외 처리
    코딩 테스트
    SpringDataJpa
    예외처리
    최적화
    코딩테스트
    스프링 컨테이너
    재귀
    다형성
    BFS
    컬렉션
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[백준] 1781 컵라면 (JAVA)
상단으로

티스토리툴바