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

12 ljedd2 #164

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

12 ljedd2 #164

wants to merge 10 commits into from

Conversation

LJEDD2
Copy link
Collaborator

@LJEDD2 LJEDD2 commented Sep 25, 2024

우선순위큐 개념 익히기 마지막 문제입니다 ㅎ,ㅎ

🔗 문제 링크

백준 우선순위 큐 | BOJ 15903 카드 합체 놀이

문제 설명

자연수가 쓰여진 카드를 n장 갖고 있다. 처음에 i번 카드엔 ai가 쓰여있다. 카드 합체 놀이는 이 카드들을 합체하며 노는 놀이이다. 카드 합체는 다음과 같은 과정으로 이루어진다.

  1. x번 카드와 y번 카드를 골라 그 두 장에 쓰여진 수를 더한 값을 계산한다. (x ≠ y)
  2. 계산한 값을 x번 카드와 y번 카드 두 장 모두에 덮어 쓴다.

이 카드 합체를 총 m번 하면 놀이가 끝난다.
m번의 합체를 모두 끝낸 뒤, n장의 카드에 쓰여있는 수를 모두 더한 값이 이 놀이의 점수가 된다. 이 점수를 가장 작게 만드는 것이 놀이의 목표이다.

제한 조건

  • 입력 첫 번째 줄에 카드의 개수를 나타내는 수 n(2 ≤ n ≤ 1,000)과 카드 합체를 몇 번 하는지를 나타내는 수 m(0 ≤ m ≤ 15×n)이 주어진다.

  • 입력 두 번째 줄에 맨 처음 카드의 상태를 나타내는 n개의 자연수 a1, a2, …, an이 공백으로 구분되어 주어진다. (1 ≤ ai ≤ 1,000,000)

✔️ 소요된 시간

40분

✨ 수도 코드

앞서 풀었던 카드 정렬하기 문제와 동일한 방식으로 접근하였습니다.

문제의 조건이 합이 되는 값이 비교 요소 두 개에 모두 덮어씌워지기 때문에 이 부분을 참고하여 문제를 해결할 수 있었습니다.

  1. x번 카드와 y번 카드를 골라 그 두 장에 쓰여진 수를 더한 값을 계산
    2) 계산한 값을 x번 카드와 y번 카드 두 장 모두에 덮어씀
  2. n장의 카드에 쓰여있는 수를 모두 더한 값이 최소가 되어야 함

전체 카드의 합을 가장 작게 하려면, 카드 더미에서 가장 작은 두 수를 골라 두 수의 합을 덮어쓰는 과정을 반복하면 됩니다.

따라서 코드로 그대로 작성하면 아래와 같습니다.
우선순위 큐 개념을 익히고 간단하게 풀어볼 수 있었던 문제였습니다 !

최종 코드

import heapq
n, m = map(int,input().split())

#힙 구조로 변환 
numbers = list(map(int,input().split()))
heapq.heapify(numbers)

for _ in range(m):

    x = heapq.heappop(numbers)
    y = heapq.heappop(numbers)

    # x와 y 둘 다 값 교체 
    heapq.heappush(numbers, x+y)
    heapq.heappush(numbers, x+y)

print(sum(numbers))

📚 새롭게 알게된 내용

  • heap에서 삽입 연산의 시간 복잡도는 O(logn)으로, 훨씬 효율적
  • Python에서 heapq 내장 모듈을 통해 쉽게 힙을 구현할 수 있지만 heap이 그 자체로 별도의 자료구조는 아니라는 점 유의
  • heap을 생성하는 대신, 빈 리스트를 생성한 뒤 heapq 모듈을 통해 리스트를 heap으로 취급하여 사용이 가능

@LJEDD2 LJEDD2 marked this pull request as draft September 25, 2024 15:17
@LJEDD2 LJEDD2 marked this pull request as ready for review September 25, 2024 15:35
@LJEDD2 LJEDD2 self-assigned this Sep 25, 2024
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.

우선순위 큐를 마스터하신 것 같군요! 대단하십니당..😲👍
저도 카드 정렬하기 문제와 동일한 방식으로 접근하여서 카드 더미에서 가장 작은 두 수를 골라서 두 수의 합을 덮어쓰는 로직으로 풀어보았습니다! 우선순위 큐 개념을 완벽하게 써먹을 수 있었던 문제인 것 같네요😊

이번 PR도 수고하셨습니다!

Copy link
Member

@jung0115 jung0115 left a comment

Choose a reason for hiding this comment

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

저도 같은 방법으로 풀었습니다! 덕분에 저도 우선순위 큐에 익숙해지고 있는 것 같아요

public class Num15903 {
  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 m = Integer.parseInt(st.nextToken());

    long[] cardStatus = new long[n];
    st = new StringTokenizer(br.readLine());
    for(int i = 0; i < n; i++) {
      cardStatus[i] = Long.parseLong(st.nextToken());
    }

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

    for(int i = 0; i < n; i++) {
      pq.add(cardStatus[i]);
    }

  for(int i = 0; i < m; i++) {
    long a = pq.poll();
    long b = pq.poll();

    pq.add(a + b);
    pq.add(a + b);
    }

    long answer = 0;
    
    
    while(!pq.isEmpty()) {
      answer += pq.poll();
    }

    System.out.println(answer);
  }
}

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.

3 participants