AcWing 110 防晒

题目描述:

有C头奶牛进行日光浴,第i头奶牛需要minSPF[i]到maxSPF[i]单位强度之间的阳光。每头奶牛在日光浴前必须涂防晒霜,防晒霜有L种,涂上第i种之后,身体接收到的阳光强度就会稳定为SPF[i],第i种防晒霜有cover[i]瓶。求最多可以满足多少头奶牛进行日光浴。

输入格式

第一行输入整数C和L。接下来的C行,按次序每行输入一头牛的minSPF和maxSPF值,即第i行输入minSPF[i]和maxSPF[i]。再接下来的L行,按次序每行输入一种防晒霜的SPF和cover值,即第i行输入SPF[i]和cover[i]。每行的数据之间用空格隔开。

输出格式

输出一个整数,代表最多可以满足奶牛日光浴的奶牛数目。

数据范围

1≤C,L≤2500,1≤minSPF≤maxSPF≤1000,1≤SPF≤1000

输入样例:

3 2
3 10
2 5
1 5
6 2
4 1

输出样例:

2

分析:

扫描二维码关注公众号,回复: 6097257 查看本文章

本题是经典区间贪心的一类变形。在区间问题中,我们一般按照结束时间进行排序,优先选择最晚结束时间的区间;或者按照开始时间从大到小排序,优先选择最晚开始时间。本题需要相当细心,很容易出错。

第一个需要注意的是一般区间问题选择了这个区间,便可以继续考察下一个区间了,具有单调性。而本题不具有该性质,用双指针的话会出错。下面先介绍两种思路。

方法一:按照奶牛的最大spf排序,然后从符合条件的防晒霜中选择最小spf的一个。

格外需要注意的是,这里的区间是奶牛的spf,点是防晒霜的spf,我们在给第一头奶牛选择出了适合它的防晒霜后,适合第二头的防晒霜的spf可能比之前选出的大,也可能比之前的小,因为符合他们要求的防晒霜并不是相同的集合。

实现方式很灵活,贪心的一般思路需要排序,按照奶牛最大的spf排序,不需要写个cmp。完全可以利用sort给结构体排序时默认按照第一个成员大小进行排序的性质,将maxspf作为奶牛spf二元组的第一个变量即可。之后再对防晒霜进行排序。

最后为每头奶牛依次枚举符合条件的防晒霜,最小符合条件的即是spf最小的防晒霜。

#include <iostream>
#include <algorithm>
using namespace std;
pair<int,int> a[2550],b[2550];
int main(){
    int c,l,ans = 0;
    cin>>c>>l;
    for(int i = 0;i < c;i++)    cin>>a[i].second>>a[i].first;
    for(int i = 0;i < l;i++)    cin>>b[i].first>>b[i].second;
    sort(a,a + c);
    sort(b,b + l);
    for(int i = 0;i < c;i++){
        for(int j = 0;j < l;j++){
            if(b[j].second && a[i].second <= b[j].first && a[i].first >= b[j].first){
                ans++;
                b[j].second--;
                break;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

方法二:按照奶牛的最小spf从大到小排序,然后从符合条件的防晒霜中选择最大spf的一个。

按照奶牛的最小spf从大到小排序,同样不用刻意写cmp(能偷懒绝不多写几行)。我们按照minspf从小到大排序,之后倒着枚举即可。防晒霜也是一样,排序后倒着枚举最先找到的即是spf最大的一个。

#include <iostream>
#include <algorithm>
using namespace std;
pair<int,int> a[2550],b[2550];
int main(){
    int c,l,ans = 0;
    cin>>c>>l;
    for(int i = 0;i < c;i++)    cin>>a[i].first>>a[i].second;
    for(int i = 0;i < l;i++)    cin>>b[i].first>>b[i].second;
    sort(a,a + c);
    sort(b,b + l);
    for(int i = c - 1;i >= 0;i--){
        for(int j = l - 1;j >= 0;j--){
            if(b[j].second && a[i].first <= b[j].first && a[i].second >= b[j].first){
                ans++;
                b[j].second--;
                break;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

最后简单分析下这两种思路成立的原因。 按照奶牛的最大spf排序,在符合条件的防晒霜中优先选取最小spf的那个。比如x和y都符合奶牛的条件,spf值x < y,若x被选取,则y也可能符合下一头奶牛(最大spf更大)的要求;反之若选择了y,很可能x就不再符合下一头奶牛的要求了。或者说,对于当前奶牛,x和y均可用,而对于下一头奶牛,若x可用,则给当前奶牛还是下一头均对答案贡献一样,都是一头,若y可用,下一头牛就可以使用y了。会不会存在对于当前奶牛x,y均可用,而下一头牛x可用,y不可用的情况呢?不会的,因为当前奶牛的区间包含了x,y,若下一头牛包含x,且区间右端点大于当前牛,那么必然也包含y。(画个图就显而易见了)。第二种思路的原理也是一样。可能表达得不够清楚,但是区间贪心十有八九都是这两种策略是正确的,即使不知道原理,也是可以使用的。

猜你喜欢

转载自blog.csdn.net/qq_30277239/article/details/88919106
110