题目链接
https://vjudge.net/problem/POJ-3614
题目大意
有C头奶牛晒日光浴,第i头奶牛需要minSPF[i]至maxSPF[i]之间的日光强度。现在有L个防晒霜,第i个防晒霜可以使日光强度控制在SPF[i],可以供cover[i]头奶牛使用,求最多能满足多少头奶牛。
解题思路
贪心,<stron>。</stron>
因为同时有上限和下限约束着防晒霜的使用,所以贪心策略不一样。需要先去掉一个约束再执行贪心策略,所以从小打到枚举每一种防晒霜,对于每一种防晒霜,我们需要先找出所有spf下限小于它 的牛,然后再贪心选出可以使用防晒霜的spf上限最小的牛,就能得到最优解了。用了优先队列实现。
把每头奶牛按照minSPF[i]的值从小到大排序,把防晒霜也按照SPF[i]的值从小到大排序,加一个优先队列,让maxSPF[i]小的奶牛先使用防晒霜。
AC代码
//注释较长,建议复制下来,自行调整长度后阅读 #include<iostream> #include<queue> #include<algorithm> using namespace std; const int N=3000; int n,m,cnt=1,ans; priority_queue<int,vector<int>,greater<int> > q;//优先队列可以很好的解决个数的问题//为什么用小根堆下面就知道了 struct node { int l,r; }a[N],b[N];//a表示牛,b表示防晒霜 bool cmp(node c,node d) { return c.l<d.l;//对于牛而言只按minSPF排序就行(看完下面就知道了),对于防晒霜而言也是只按SPF排序就行(看完下面就知道了) } int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r; for(int i=1;i<=m;i++) cin>>b[i].l>>b[i].r; sort(a+1,a+n+1,cmp); sort(b+1,b+m+1,cmp); for(int i=1;i<=m;i++)//!!!遍历的是防晒霜!!! { while(cnt<=n && a[cnt].l<=b[i].l) q.push(a[cnt].r),++cnt;//将区间左端点小于当前防晒霜的区间右端点压入优先队列中//我们管的只是区间左端点,只要是左端点满足条件的都会被压入队列中,所以排序不用管右端点的大小,而且优先队列中本来就是排好序的;防晒霜的个数那就更没影响了,甚至SPF相同的防晒霜的个数都可以合起来,对吧。 while(!q.empty() && b[i].r)//队列不空并且当前这种防晒霜没用完 { int tmp=q.top();q.pop();//从右端点最小的开始取 if(tmp>=b[i].l) ++ans,--b[i].r;//要是取出的值小于当前防晒霜,那就直接弹没了,什么都不影响,因为当前防晒霜比之后的防晒霜要小,而这头牛小的都用不了,大的更用不了了;这也是为什么用小根堆,可以直接把过小的弹没,即使当前种类的防晒霜数量不够,我们也可以把大的留在队列里,试试能不能用下一个防晒霜;当前要是取出的可以用,那就用。 } } cout<<ans<<endl; return 0; }
另附例题
https://blog.nowcoder.net/n/392777c2fc324bc88be4ff187a479554