레이블이 priority queue인 게시물을 표시합니다. 모든 게시물 표시
레이블이 priority queue인 게시물을 표시합니다. 모든 게시물 표시

2018년 6월 6일 수요일

15708 미네크래프트

15708 미네크래프트 https://www.acmicpc.net/problem/15708
Codeforces #470 (Div.2) C - Producing Snow http://codeforces.com/contest/948/problem/C
14452 Cow Dance Show https://www.acmicpc.net/problem/14452
1781 컵라면 https://www.acmicpc.net/problem/1781   (https://lyzqm.blogspot.com/2017/10/1781.html)

pqgreedy를 이용한 문제들을 소개하고자 한다.

1. 미네크래프트
시간 TN개의 바위를 각각 캐는데 걸리는 시간이 주어지고 옆의 바위로 건너가는 시간P가 주어진다.
캘 수 있는 바위의 최대개수를 구하는 문제이다.

현재 보고있는 바위를 캘지 정하는 것으로 풀지 말고 
지금 까지 봤던 바위들 중 작은 바위들을 캐서 현재 보고있는 바위까지 건너올 수 있게끔 풀어야 한다.

이러한 유형의 문제들은 우선적으로 pq에 넣어서 처리해주는 편이 좋다.
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, t, p;
int arr[MAXN];
priority_queue<int> pq;
int main() {
    scanf("%d%d%d"&n, &t, &p);
    for (int i = 0; i < n; i++scanf("%d"&arr[i]);
    int sum = 0, sze = 0, ans = 0;
    for (int i = 0; i < n; i++) {
        if (t <= p * i) break;
        sze++;
        sum += arr[i];
        pq.push(arr[i]);
        while (!pq.empty() && sum > t) {
            sum -= pq.top();
            sze--;
            pq.pop();
        }
        if (sum > t) break;
        ans = max(ans, sze);
        sum += p;
    }
    printf("%d\n", ans);
    return 0;
}
cs

2. Producing Snow 
N일 동안 눈이 $s_{i}$만큼 쌓인다.
각각의 날에 기온은 $t_{i}$이다.
눈이 녹는 정도는 그날 기온에 영향을 받으며 이전에 남았던 눈 또한 녹는다.
각각의 날에 녹는 눈의 양을 구하는 문제이다.


대회때는 못풀었던 아쉬운 문제이다.
pq에 $s_{i}$와 이전에 기온들의 합을 넣어 관리할 수 있다.
눈이 완전히 녹는것은 이전 기온들의 합과 현재 기온의 합보다 작거나 같아지는 경우이다.
아직 pq에 남아있는 크기만큼 눈들 또한 더 녹기 때문에 이것도 더해줘야한다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int MAXN = 1e5 + 5;
int arr[MAXN];
priority_queue<ll> pq;
int main() {
    scanf("%d"&n);
    for (int i = 0; i < n; i++scanf("%d"&arr[i]);
    ll s = 0;
    for (int i = 0, minus; i < n; i++) {
        ll ret = 0;
        scanf("%d"&minus);
        pq.push(-(arr[i] + s));
        s += minus;
        while (!pq.empty() && -pq.top() <= s) {
            ret += -pq.top() - s + minus;
            pq.pop();
        }
        ret += pq.size() * minus;
        printf("%lld ", ret);
    }
    return 0;
}
cs

3. Cow Dance Snow
소들이 춤추는 시간들이 정해져있고 춤을 다 춘 소는 순차적으로 들어간다.
모든 소가 춤을 추는데 걸리는 시간 T를 넘지 않도록 소들이 춤출 수 있는 
최소 사이즈 K를 구하는 문제다. 

이분탐색과 위의 문제처럼 pq를 이용한 기법으로 해결할 수 있다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 6;
int n, t;
ll arr[MAXN];
bool ispossible(int idx) {
    ll prv = 0, sum = 0;
    priority_queue<ll> pq;
    for (int i = 0; i < idx; i++) pq.push(-arr[i]);
    while (!pq.empty()) {
        ll curr = -pq.top();
        pq.pop();
        sum += (curr - prv);
        if (sum > t) return false;
        prv = curr;
        if (idx < n) pq.push(-sum - arr[idx++]);
    }
    return sum <= t;
}
int main() {
    scanf("%d%d"&n, &t);
    for (int i = 0; i < n; i++scanf("%lld"&arr[i]);
    
    int l = 1, r = n;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (ispossible(mid)) r = mid - 1;
        else l = mid + 1;
    }
    printf("%d\n", l);
    return 0;
}
cs

2018년 1월 28일 일요일

12764 싸지방에 간 준하

12764 싸지방에 간 준하 https://www.acmicpc.net/problem/12764

사용자의 컴퓨터 시작 시간과 끝 시간이 주어진다.
사용자는 비어있는 자리중 가장 작은 번호부터 사용한다.
컴퓨터를 최소한으로 사용할 때 그 개수와 자리별 사용회수를 구하는 문제이다.

우선순위 큐로 해결 할 수 있다.
사용자를 시작시간 순으로 정렬시킨 후 우선순위 큐에서 종료되어 나오는 사용자들을 관리해 준다.
set으로 종료되어 나오는 사용자들의 자리 번호를 관리해주면 된다.

#include <cstdio>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
int N;
pair<intint> p[100001];
set<int> save;
int ans[100001];
int solve() {
    priority_queue<pair<intint>> pq;
    int size = 0;
    for (int n = 0; n < N; n++) {
        while (!pq.empty()) {
            if (-pq.top().first <= p[n].first) {
                save.insert(pq.top().second);
                pq.pop();
            }
            else break;
        }
        if (save.empty()) {
            pq.push({ -p[n].second, size });
            ans[size++]++;
        }
        else {
            auto idx = save.begin();
            pq.push({ -p[n].second, *idx });
            ans[*idx]++;
            save.erase(idx);
        }
    }
    return size;
}
int main() {
    scanf("%d"&N);
    for (int n = 0; n < N; n++scanf("%d%d"&p[n].first, &p[n].second);
    sort(p, p + N);
 
    int M = solve();
    printf("%d\n", M);
    for (int m = 0; m < M; m++printf("%d ", ans[m]);
    return 0;
}
cs


2017년 10월 19일 목요일

1781 컵라면

1781 컵라면 https://www.acmicpc.net/problem/1781

문제에 dead line이 있고 그 문제를 dead line 안에 해결하면 컵라면이 주어진다.
문제를 푸는데는 1이 걸리며 최대로 받을 수 있는 컵라면의 개수를 구하는 문제다.

greedy하게 해결할 수 있다.
dead line을 오름차순으로 정렬하고 받을 수 있는 컵라면 개수는 내림차순으로 정렬해보자.

현재 시간이 지금 컵라면의 dead line보다 작거나 같으면 min heap에 삽입한다.

위의 경우가 아니고 min heaptop값이 현재 컵라면의 개수보다 작으면 
min heaptop값과 현재 컵라면의 개수를 서로 교환해준다.
이것이 성립하는 이유는 현재 min heap에 들어있는 컵라면들의 dead line
현재 컵라면의 dead line보다 작거나 같음이 보장되기 때문이다.
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
struct Cup {
    int dead, num;
};
int N;
Cup cup[200001];
int main() {
    scanf("%d"&N);
    for (int n = 0;n < N;n++scanf("%d%d"&cup[n].dead, &cup[n].num);
    sort(cup, cup + N, [](Cup &a, Cup &b)->bool {
        return a.dead == b.dead ? a.num > b.num : a.dead < b.dead;
    });
    priority_queue<int> pq;
    int cnt = 1;
    int ans = 0;
    for (int n = 0;n < N;n++) {    
        if (cnt <= cup[n].dead) {
            cnt++;
            pq.push(-cup[n].num);
            ans += cup[n].num;
        }
        else if (!pq.empty() && -pq.top() < cup[n].num) {
            ans += (cup[n].num + pq.top());        //top은 빼주고 cup은 더해준다.    
            pq.pop();
            pq.push(-cup[n].num);
        }
    }
    printf("%d\n", ans);
    return 0;
}
cs