杭电-oj sunscreen优先队列+贪心算法

Problem 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

大致题意及思路:
在这里插入图片描述
给定多少头奶牛n和多少种类防晒霜m,并且前n行放每头奶牛的最低抗晒能力和最高的防晒能力,给定防晒霜的防晒力度及他的瓶数,防晒霜防晒能力应该在这之间。

大概思路:
把防晒霜按照从小到大排序
奶牛最低抗晒能力从小到大排序
满足奶牛最低抗晒能力<防晒霜防晒能力的,就存入优先队列。优先队列按从小到大排序。然后比较奶牛最高抗晒能力是否大于防晒霜防晒能力,两个值越接近越好。因为奶牛最大晒能力越小,防晒霜防晒能力值可取区间越小,条件越苛刻,把难的搞定,其他都好说。计算满足这些情况的个数ans,输出。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 2501
#define MOD 1001
#define E 1e-12
using namespace std;
struct Cow
{
    int maxx;
    int minn;
}cow[N],cc;
struct Sunscreen
{
    int sum;
    int ans;
}sunscreen[N],ss;
priority_queue<int, vector<int>, greater<int> > q;
bool cmp1(Cow x,Cow y)
{
    return x.minn<y.minn;
}
bool cmp2(Sunscreen x,Sunscreen y)
{
    return x.ans<y.ans;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)//牛的防晒范围
        scanf("%d%d",&cow[i].minn,&cow[i].maxx);
    for(int i=1;i<=m;i++)//防晒霜的防晒值
        scanf("%d%d",&sunscreen[i].ans,&sunscreen[i].sum);
 
    sort(cow+1,cow+1+n,cmp1);//按牛的防晒下限升序排序
    sort(sunscreen+1,sunscreen+1+m,cmp2);//按防晒霜的防晒值升序排序
 
    int ans=0;
    int j=1;
    for(int i=1;i<=m;i++)
    {
        while(j<=n&&cow[j].minn<=sunscreen[i].ans)//从最小的防晒霜枚举,将最小值小于等于该防晒霜的奶牛的最大值放入优先队列
        {
            q.push(cow[j].maxx);
            j++;
        }
        while(sunscreen[i].sum!=0&&!q.empty())//优先队列最小值先出,可将所有最大值中的最小值取出,更新答案
        {
            int k=q.top();
            q.pop();
            if(k>=sunscreen[i].ans)
            {
                ans++;
                sunscreen[i].sum--;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

总结:

贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。

概念
贪婪算法(Greedy algorithm)是一种对某些求最优解问题的更简单、更迅速的设计技术。用贪婪法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。

贪心算法再讲
贪婪算法是一种改进了的分级处理方法。其核心是根据题意选取一种量度标准。然后将这多个输入排成这种量度标准所要求的顺序,按这种顺序一次输入一个量。如果这个输入和当前已构成在这种量度意义下的部分最佳解加在一起不能产生一个可行解,则不把此输入加到这部分解中。这种能够得到某种量度意义下最优解的分级处理方法称为贪婪算法。

对于一个给定的问题,往往可能有好几种量度标准。初看起来,这些量度标准似乎都是可取的,但实际上,用其中的大多数量度标准作贪婪处理所得到该量度意义下的最优解并不是问题的最优解,而是次优解。因此,选择能产生问题最优解的最优量度标准是使用贪婪算法的核心。

一般情况下,要选出最优量度标准并不是一件容易的事,但对某问题能选择出最优量度标准后,用贪婪算法求解则特别有效。最优解可以通过一系列局部最优的选择即贪婪选择来达到,根据当前状态做出在当前看来是最好的选择,即局部最优解选择,然后再去解做出这个选择后产生的相应的子问题。每做一次贪婪选择就将所求问题简化为一个规模更小的子问题,最终可得到问题的一个整体最优解。

基本思路
⒈建立数学模型来描述问题。

⒉把求解的问题分成若干个子问题。

⒊对每一子问题求解,得到子问题的局部最优解。

⒋把子问题的解局部最优解合成原来解问题的一个解。

实现该算法的过程:

从问题的某一初始解出发;

while 能朝给定总目标前进一步 do

求出可行解的一个解元素;

由所有解元素组合成问题的一个可行解。

下面是一个可以试用贪心算法解的题目,贪心解的确不错,可惜不是最优解。

例题分析
[0-1背包问题]有一个背包,背包容量是M=150。有7个物品,物品不可以分割成任意大小。

要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

物品 A B C D E F G

重量 35 30 60 50 40 10 25

价值 10 40 30 50 35 40 30

分析:

目标函数:∑pi最大

约束条件是装入的物品总重量不超过背包容量:∑wi<=M(M=150)

⑴根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

⑵每次挑选所占重量最小的物品装入是否能得到最优解?

⑶每次选取单位重量价值最大的物品,成为解本题的策略。

值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。

贪心算法还是很常见的算法之一,这是由于它简单易行,构造贪心策略不是很困难。

可惜的是,它需要证明后才能真正运用到题目的算法中。

一般来说,贪心算法的证明围绕着:整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。

对于例题中的3种贪心策略,都是无法成立(无法被证明)的,解释如下:

⑴贪心策略:选取价值最大者。

反例:

W=30

物品:A B C

重量:28 12 12

价值:30 20 20

根据策略,首先选取物品A,接下来就无法再选取了,可是,选取B、C则更好。

⑵贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。

⑶贪心策略:选取单位重量价值最大的物品。

反例:

W=30

物品:A B C

重量:28 20 10

价值:28 20 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。

【注意:如果物品可以分割为任意大小,那么策略3可得最优解】

对于选取单位重量价值最大的物品这个策略,可以再加一条优化的规则:对于单位重量价值一样的,则优先选择重量小的!这样,上面的反例就解决了。

但是,如果题目是如下所示,这个策略就也不行了。

W=40

物品:A B C

重量:25 20 15

价值:25 20 15

附:本题是个DP问题,用贪心法并不一定可以求得最优解,以后了解了动态规划算法后本题就有了新的解法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值