반응형

문제 링크

 

11286번: 절댓값 힙

첫째 줄에 연산의 개수 N(1≤N≤100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 0이 아니라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0

www.acmicpc.net

 

풀이 ) 우선순위큐

문제 조건에 따라 우선순위큐에 넣었다가 빼주면된다.

뺄 때 조건은 절댓값이 같을 때는 작은값 즉 음수를 꺼내고, 절댓값이 다를때는 절댓값이 작은값을 꺼내주면 된다.

 

import java.io.*;
import java.util.PriorityQueue;

public class Main {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder answer = new StringBuilder();

        int n = Integer.parseInt(br.readLine());

        PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2)->{
            if(Math.abs(o1) == Math.abs(o2)) {
                return o1-o2;
            } else {
                return Math.abs(o1)-Math.abs(o2);
            }
        });
        while(n-- > 0) {
            int x = Integer.parseInt(br.readLine());

            if(x == 0) {
                if(pq.isEmpty()) {
                    answer.append(0).append('\n');
                } else {
                    answer.append(pq.poll()).append('\n');
                }
            } else {
                pq.offer(x);
            }
        }

        System.out.println(answer.toString());
    }
}
반응형
반응형

문제 링크

 

17612번: 쇼핑몰

입력의 첫 줄에는 2개의 정수 N(1 ≤ N ≤ 100,000)과 k(1 ≤ k ≤ 100,000)가 주어진다. 다음 줄부터 N개의 줄에 걸쳐 고객 N명의 정보가 줄 맨 앞의 고객부터 맨 뒤 고객까지 순서대로 주어진다. i번째

www.acmicpc.net

 

풀이 ) 우선순위큐

  처음에는 큐를 이용해서 완전탐색을 하는 방식으로 구현하려했지만 이럴 때의 시간복잡도는 O(nk)가 되고 n과 k가 각각 10만 이하이므로 완전탐색으로는 해결할 수 없었다.

 

  계산대를 이용하는 고객을 저장하는 우선순위큐를 만들어서, 끝나는 시간이 빠르고 이용하는 계산대의 번호가 큰 순서대로 우선순위가 높게 만들었다.

 

  손님을 줄세우고 먼저 계산대에 모두 채워 넣는다. (* 이때 계산대의 수에 조심하지 않으면 null pointer exception 발생)

 

  이후 계산이 가장 빨리 끝나는 고객의 시간으로 시간을 갱신한 이후(time = counter.peek().time), 해당 시간에 계산이 끝나는 고객을 모두 제거하고(pollAt(time)) 비어있는 계산대에 손님으로 채운다.(offerAt(time))

  

import java.io.*;
import java.util.*;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringTokenizer st;

    static int n, k;
    static Queue<Info> customers = new LinkedList<>();	// 고객 줄
    static PriorityQueue<Info> counters = new PriorityQueue<>((o1, o2)->{
        if(o1.time == o2.time)
            return o2.num-o1.num;
        return o1.time-o2.time;
    });		// 끝나는 시간이 짧고, 계산대 번호가 큰 순서대로 제거하는 우선순위큐
    static Stack<Integer> vacancy = new Stack<>();	// 비어있는 계산대
    static long answer;		// 결과
    static int nFinish;		// 계산 끝난 사람 수

    public static void main(String[] args) throws IOException {
        input();
        solve();
    }

    static void solve() throws IOException {
        int time = 0;
        for(int i = 0; i < k; ++i){		// 처음 k명 계산대 이용
            if(customers.isEmpty())		// * 주의사항: 계산대수 > 고객수
                break;
            Info customer = customers.poll();
            customer.time = customer.w;
            customer.num = i;
            counters.offer(customer);
        }
        while(!customers.isEmpty()){
            if(!counters.isEmpty())
                time = counters.peek().time;	// 시간 갱신
            pollAt(time);
            offerAt(time);
        }

        while(!counters.isEmpty())	// 줄이 없는 상태에서 계산대 이용중인 고객 계산
            answer += 1L * (++nFinish) * counters.poll().id;

        bw.write(answer+" ");
        bw.flush();
    }

    static void pollAt(int time){	// time 시간에 계산을 마치는 고객 모두 계산대에서 제거
        while(!counters.isEmpty()){
            Info counter = counters.peek();
            if(counter.time == time){	// 가장 빨리 끝나는 고객의 시간이 현재시간이면 제거
                counters.poll();
                vacancy.push(counter.num);	// 비어있는 계산대 추가
                answer += 1L * (++nFinish) * counter.id;	// 정답 추가
            }
            else
                break;
        }
    }

    static void offerAt(int time){	// time 시간에 빈 계산대에 고객 채우기
        while(!customers.isEmpty() && !vacancy.isEmpty()){
            Info customer = customers.poll();
            customer.num = vacancy.pop();	// 비어있는 계산대 이용
            customer.time = time+customer.w;	// 계산대 이용하는 고객의 끝 시간 갱신
            counters.offer(customer);		// 계산대 이용
        }
    }

    static void input() throws IOException {
        st = new StringTokenizer(br.readLine(), " ");
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        for(int i = 0; i < n; ++i){
            st = new StringTokenizer(br.readLine(), " ");
            customers.offer(new Info(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())));
        }
    }

    static class Info{
        int id, w, time, num;
        // id: 고객의 회원번호
        // w: 물건 개수(계산 소요 시간)
        // time: 계산을 마치는 시간
        // num: 이용하는 계산대 번호 

        public Info(int id, int w) {
            this.id = id;
            this.w = w;
        }
    }
}

 

주의 )

  • 계산대의 수가 손님보다 많은 경우
반응형

+ Recent posts