poj3614 Sunscreen

题目:

Description
To avoid unsightly burns while tanning, each of the C (1 ≤ C ≤ 2500) cows must cover her hide with sunscreen when they're at the beach. Cow i has a minimum and maximum SPF rating (1 ≤ minSPFi ≤ 1,000; minSPFi ≤ maxSPFi ≤ 1,000) that will work. If the SPF rating is too low, the cow suffers sunburn; if the SPF rating is too high, the cow doesn't tan at all........
The cows have a picnic basket with L (1 ≤ L ≤ 2500) bottles of sunscreen lotion, each bottle i with an SPF rating SPFi (1 ≤ SPFi ≤ 1,000). Lotion bottle i can cover coveri cows with lotion. A cow may lotion from only one bottle.
What is the maximum number of cows that can protect themselves while tanning given the available lotions?
Input

  • Line 1: Two space-separated integers: C and L
  • Lines 2..C+1: Line i describes cow i's lotion requires with two integers: minSPFi and maxSPFi
  • Lines C+2..C+L+1: Line i+C+1 describes a sunscreen lotion bottle i with space-separated integers: SPFi and coveri
    Output
    A single line with an integer that is the maximum number of cows that can be protected while tanning
    Sample Input
    3 2
    3 10
    2 5
    1 5
    6 2
    4 1
    Sample Output
    2

这道题在刚学优先队列时做过一次,当时费了许多精力,参考了大神们的文章,好不容易解决了。在很久之后的今天,又遇到了这道题,本以为会轻松解决,结果还是遇到了不小的麻烦,最后终于又一次解决了,但还是有些地方不太明白。写这篇文章来整理一下。

题意:有一群牛要晒太阳,每头牛都有spf值的下限和上限。如果阳光的spf值低于下限,则这头牛没有效果。但如果阳光的spf值高于上限,则会烧伤这头牛的皮肤。但太阳特别强烈,因此有一些不同spf值和不同数量的防晒霜。牛涂上之后阳光的spf值就变为防晒霜的spf值,只要在牛的spf的范围之内牛就能晒太阳。问最多可以让多少头牛晒太阳。

每头牛只能涂一个防晒霜,要求最大值,所以可以用贪心策略。
将防晒霜依据spf值从小到大排序,将牛按照spf下限值从小到大的顺序排序,下限值相同的按照spf上限值从小到大的顺序排序。
防晒霜从spf值小的种类开始,牛按照spf下限小的值开始。从小的值开始,就可以给大的留更多的防晒霜。我的理解是:如果给一个spf上限本来就不大的牛分了一个spf值在他范围内但很大的防晒霜,可能之后有一头spf下限很高的牛就拿不到了。
对于每一种防晒霜,只要这些牛中有下限小于等于它的就把这头牛的spf上限值进入最小堆中维护,如果不满足则轮下一种防晒霜。满足下限条件的牛只需要每次从最小堆中取出一个值(从小spf上限开始取),只要符合条件并且这种防晒霜还够就可以使用,计数器加1.如果这一种防晒霜分完了并且堆中还没空,就证明这种防晒霜已经用完了,需要轮到后面spf值大的防晒霜再判断。

参考代码:

#include 
#include 
#include 
using namespace std;
const int N = 2500+5;
const int M = 2500+5;

struct Cow {
    int mins;//最小SPF值
    int maxs;//最大SPF值
} cow[N];

struct Scr {
    int spf;//此防晒霜的SPF值 
    int cover;//此防晒霜最多可用于多少头牛
} scr[M];

int C, L;
int sz;
bool ok[N];

bool cmp(const Scr &x, const Scr &y) {
    return x.spf < y.spf;
}

bool cmp1(const Cow &x, const Cow &y) {
    if (x.mins != y.mins) return x.mins < y.mins;
    return x.maxs < y.maxs;
}

int heap[N];

void init() {
    memset(cow, 0, sizeof(cow));
    memset(scr, 0, sizeof(scr));
    memset(heap, 0, sizeof(heap));
    memset(ok, 0, sizeof(ok));
    sz = 0;
}

void push(int x) {//按照maxs的顺序从小到大

    int i = sz++;//i代表当前的下标, 然后sz加1, 代表当前数组的长度
    while (i > 0) {
        int p = (i - 1) / 2;//父亲节点的编号
        if (heap[p] <= x) break;//如果已经没有大小颠倒则退出
        //把父亲节点的数值放下来, 而把自己提上去
        heap[i] = heap[p];
        i = p;
    }

    heap[i] = x;
}

int pop() {
    //弹出maxs最小的节点
    int ret = heap[0];
    //要提到根的数值
    int x = heap[--sz];
    //从根开始向下交换
    int i = 0;
    while (i * 2 + 1 < sz) {
        //比较儿子的值
        int a = i * 2 + 1;
        int b = i * 2 + 2;
        if (b < sz && heap[b] < heap[a]) a = b;
        //如果已经没有大小颠倒则退出
        if (heap[a] >= x) break;
        //把儿子的数值提上来
        heap[i] = heap[a];
        i = a;
    }

    heap[i] = x;
    return ret;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    while (cin >> C >> L) {
        init();
        int mins, maxs;
        for (int i = 0;i < C;++i) {
            cin >> cow[i].mins >> cow[i].maxs;
        }

        for (int i = 0;i < L;++i) {
            cin >> scr[i].spf >> scr[i].cover;
        }

        sort(scr, scr+L, cmp);
        sort(cow, cow+C, cmp1);

        int cnt = 0;
        
        int j = 0;
        for (int i = 0;i < L;++i) {
            while (j < C && cow[j].mins <= scr[i].spf) {
                //cout << cow[j].maxs << endl;
                push(cow[j].maxs);
                ++j;
            }

            while (sz > 0 && scr[i].cover) {
                int ret = pop();
                if (ret >= scr[i].spf) {
                    ++cnt;
                    --scr[i].cover;
                }   
            }
        }

        cout << cnt << endl;
    }
    return 0;
}

你可能感兴趣的:(poj3614 Sunscreen)