Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

14-jung0115 #165

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

14-jung0115 #165

wants to merge 15 commits into from

Conversation

jung0115
Copy link
Member

@jung0115 jung0115 commented Sep 25, 2024

1️⃣ 실패 코드
2️⃣ 정답 코드

🔗 문제 링크

백준 | 그리디 알고리즘 - 컵라면(1781)

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

image

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

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

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

✔️ 소요된 시간

1시간

✨ 수도 코드

⛔️ 실패한 풀이

처음에는 각 데드라인 시간대마다 가장 많은 컵라면을 받을 수 있는 문제를 골라서 풀면 되지 않을까? 라고 생각했습니다
그래서 데드라인이 key, 컵라면 개수가 value인 Map으로 정리하여 key값이 같은 경우 더 큰 value를 저장한 뒤, 총합을 구했습니다.

하지만 이 경우,
만약 데드라인이 1인 문제가 없고 2인 문제가 각각 2개, 3개의 컵라면을 받을 수 있을 경우
제 풀이에서는 3개의 컵라면만 받게 되는데
데드라인이 2인 것이지 시간대가 2일 때 풀어야 하는 건 아니기 때문에
시간대 1에서 3개짜리, 2에서 2개짜리를 풀어서 총 5개의 컵라면을 받을 수 있습니다.
그걸 생각하지 못하고 문제를 푼 결과... 4%에서 실패가 뜨게 되었습니다 🥹

오답 코드

public class Baekjoon_1781_fail {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int N = Integer.parseInt(br.readLine());

    HashMap<Integer, Integer> cupNoodles = new HashMap<Integer, Integer>();
    
    for(int i = 0; i < N; i++) {
      StringTokenizer st = new StringTokenizer(br.readLine());

      int deadLine = Integer.parseInt(st.nextToken()); // 데드라인
      int count = Integer.parseInt(st.nextToken());    // 맞힐 때 받는 컵라면 수

      int current = cupNoodles.getOrDefault(deadLine, 0);
      if(current < count) cupNoodles.put(deadLine, count);
    }

    int answer = 0;

    Iterator<Integer> keys = cupNoodles.keySet().iterator();
    while(keys.hasNext()){
      int key = keys.next();
      answer += cupNoodles.get(key);
    }

    System.out.print(answer);
  }
}

✅ 정답 풀이

위에서 발견한 상황을 해결하기 위해 우선순위 큐를 사용했습니다

데드라인 내에 풀 수 있는 문제인지를 판단하고, 우선순위 큐에 집어넣습니다
우선순위 큐에 들어간 문제의 수, 즉 현재 사용한 풀이 시간이 데드라인보다 많을 경우 컵라면을 적게 받는 문제를 제거해줍니다

마지막으로 우선순위 큐에 들어있는 값들을 합해주면 최대 컵라면 개수를 구할 수 있습니다

정답 코드

public class Baekjoon_1781 {
  static class CupNoodle implements Comparable<CupNoodle> {
    int deadLine;
    int count;

    public CupNoodle(int deadLine, int count) {
      this.deadLine = deadLine;
      this.count = count;
    }

    @Override
    public int compareTo(CupNoodle o) {
      // 데드라인을 기준으로 오름차순 정렬
      return this.deadLine - o.deadLine;
    }
  }

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

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

      int deadLine = Integer.parseInt(st.nextToken()); // 데드라인
      int count = Integer.parseInt(st.nextToken());    // 맞힐 때 받는 컵라면 수

      cupNoodles[i] = new CupNoodle(deadLine, count);
    }

    // 데드라인을 기준으로 정렬 (오름차순)
    Arrays.sort(cupNoodles);

    PriorityQueue<Integer> pq = new PriorityQueue<>();

    for (CupNoodle cn : cupNoodles) {
      // 만약 현재 데드라인 내에 풀 수 있는 문제라면 큐에 추가
      pq.offer(cn.count);
      
      // 큐의 크기가 데드라인을 초과하면 가장 적은 컵라면 수를 제거
      if (pq.size() > cn.deadLine) {
        pq.poll();
      }
    }

    int answer = 0;

    // 큐에 남아 있는 컵라면의 총합을 구함
    while (!pq.isEmpty()) {
      answer += pq.poll();
    }

    System.out.println(answer);
  }
}

📚 새롭게 알게된 내용

Copy link
Member

@janghw0126 janghw0126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 문제 지문을 보고난 후, 최대 컵라면 수를 구하고 데드라인 내에 풀 수 있는 문제인지 구별하라고 제시되어 있으므로 우선순위 큐 알고리즘을 이용해서 풀면 되겠다고 생각하였습니다! 그래서 데드라인이 빠른 문제부터 처리해준 후에, 데드라인이 지난 문제의 경우 이전까지 푼 문제 중 컵라면 수가 가장 적었던 문제와 비교해서 큐에 넣어주었습니다.

import heapq

n = int(input())
tasks = []

for _ in range(n):
    d, r = map(int, input().split()) 
    tasks.append((d, r))

tasks.sort()

queue = []

for task in tasks:
    heapq.heappush(queue, task[1])  
    if task[0] < len(queue): 
        heapq.heappop(queue) 

print(sum(queue))

정미님의 로직과 거의 동일하네요! 이번 PR도 수고하셨습니다😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants