ACWING110. 防晒(贪心 区间)

有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

思路:
minSPF降序排,SPF值降序排。对于每一头牛取能取的最大SPF值防晒霜。这个贪心好理解,严谨的证明可以看这里:https://www.acwing.com/solution/acwing/content/785/

这个过程可以用优先队列优化

证明:当奶牛按minSPF降序排后,对于一头奶牛,假设对应能取的SPF最大防晒霜为 SPF[y],其他能取防晒霜SPF为 SPF[x]。
存在 SPF[y] > SPF[x]。
对于后续奶牛,当SPF[y]不能取的时候,取SPF[y]是自然的。
当SPF[y]能取的时候,一定有SPF[x]能取,那么取SPF[x]和SPF[y]都一样。
而对于第一个奶牛这个决策过程是当前最优的,那么不会有后效性的影响,数学归纳后可以得到后续奶牛选择不需要考虑之前的决策,所以只考虑后续的奶牛和防晒霜条件。所以取SPF[y]更优。

在论坛的时候看到过有人问:
能不能将奶牛的单位强度按照minSPF从小到大排序,然后防晒霜也按照从小到大排序,将最小的先和最小的进行排序呢?

这样貌似和上面的解是对称的,那是对的吗?

是错的。比如(1,5) (2,3) , 和2 ,5防晒霜。
所选择的排列和决策方式,一定也要满足原解的贪心条件,也就是当前所选防晒霜如果能被后续奶牛选,其他防晒霜也必须得能被后续奶牛选,否则会出现选掉后续奶牛特有防晒霜的情况。而当前防晒霜不能被后续奶牛选的时候,选当前防晒霜没问题。
此时只有按maxSPF升序排并且选择最小SPF防晒霜才能满足这样的贪心条件。

这里有两种优先队列的写法,
一种是原解,即降序排列。对于防晒霜可选奶牛,选择当前防晒霜可选奶牛,选择minSPF最大的奶牛。
一种就是刚刚的解,即升序排列。对于防晒霜的可选奶牛,选择maxSPF最小的奶牛。

暴力算法

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn = 3005;
struct Node
{
    int x,y;
}a[maxn],b[maxn];

int cmp(Node aa,Node bb)
{
    return aa.x < bb.x;
}

int cmp2(Node aa,Node bb)
{
    return aa.x > bb.x;
}

int spf[maxn],cover[maxn];

int main()
{
    int c,l;scanf("%d%d",&c,&l);
    for(int i = 1;i <= c;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    sort(a + 1,a + 1 + c,cmp2);
    for(int i = 1;i <= l;i++)
    {
        scanf("%d%d",&b[i].x,&b[i].y);
    }
    int ans = 0;
    sort(b + 1,b + 1 + l,cmp2);
    for(int i = 1;i <= c;i++)
    {
        for(int j = 1;j <= l;j++)
        {
            if(b[j].x >= a[i].x && b[j].x <= a[i].y && b[j].y > 0)
            {
                b[j].y--;ans++;
                break;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

优先队列1

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 2550;
struct Node
{
    int x,y;
    bool operator < (const Node&rhs)const
    {
        return x < rhs.x;
    }
}a[maxn],b[maxn];

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    for(int i = 1;i <= m;i++)
    {
        scanf("%d%d",&b[i].x,&b[i].y);
    }
    sort(a + 1,a + 1 + n);
    sort(b + 1,b + 1 + m);
    priority_queue<int>q;
    int cnt = 1,ans = 0;
    for(int i = 1;i <= m;i++)
    {
        while((cnt <= n) && a[cnt].x <= b[i].x)
        {
            q.push(-a[cnt++].y);
        }
        while(!q.empty() && -q.top() < b[i].x)
        {
            q.pop();
        }
        while(!q.empty() && b[i].y)
        {
            ans++;q.pop();--b[i].y;
        }
    }
    printf("%d\n",ans);
    return 0;
}

优先队列2

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 2550;
struct Node1
{
    int x,y;
    bool operator < (const Node1&rhs)const
    {
        return y > rhs.y;
    }
}a[maxn];

struct Node2
{
    int x,y;
    bool operator < (const Node2&rhs)const
    {
        return x > rhs.x;
    }
}b[maxn];

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    for(int i = 1;i <= m;i++)
    {
        scanf("%d%d",&b[i].x,&b[i].y);
    }
    sort(a + 1,a + 1 + n);
    sort(b + 1,b + 1 + m);
    priority_queue<int>q;
    int cnt = 1,ans = 0;
    for(int i = 1;i <= m;i++)
    {
        while((cnt <= n) && a[cnt].y >= b[i].x)
        {
            q.push(a[cnt++].x);
        }
        while(!q.empty() && q.top() > b[i].x)
        {
            q.pop();
        }
        while(!q.empty() && b[i].y)
        {
            ans++;q.pop();--b[i].y;
        }
    }
    printf("%d\n",ans);
    return 0;
}

map迭代器二分写法

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;

struct Node
{
    int x,y;
}a[3005];

int cmp1(Node aa,Node bb)
{
    return aa.x > bb.x;
}

map<int,int>mp;

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)scanf("%d%d",&a[i].x,&a[i].y);
    for(int i = 1;i <= m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        mp[x] += y;
    }
    sort(a + 1,a + 1 + n,cmp1);
    mp[0] = 0;//保证it不为空能够it--
    mp[3005] = 0;//保证二分的到
    int ans = 0;
    map<int,int>::iterator it;
    for(int i = 1;i <= n;i++)
    {
        it = mp.upper_bound(a[i].y);
        it--;
        if(it -> first >= a[i].x)
        {
            ans++;
            it -> second--;
            if(!(it -> second))
            {
                mp.erase(it);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

发布了756 篇原创文章 · 获赞 27 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104504218