题目:
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 <iostream>
#include <cstring>
#include <algorithm>
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;
}