基本算法之贪心算法

防嗮

题目链接

解题思路:

我们首先将奶牛可以承受的最小值,递减排序,也就是降序排列,然后将防晒霜固定的值,递减排序,还是降序排列.
对于每一个头奶牛而言,当然是要选择目前来说满足条件的最差的防晒霜,什么最差的定义,就是选择满足奶牛条件的SPF最大的那一瓶防晒霜.
注意:降序排序,保证对于每一头牛而言,它用的是,可以使用的最差的防晒霜,因为值越小的防晒霜,有可能让更多的牛使用.而升序排列,就恰好反了. 注意:如果一头牛没有合适的防嗮霜给它了就不用管他了。

难点:

  • 如何高效的找到小于等于一个值的最大值
  • 如何动态删除一个元素。(用完了要删除)
  • 区间排序

技巧:

  • 以上两个操作是平衡树的两个基本操作因此我们可以使用平衡树来解决。在STL中有map 和 set
  • 对于区间来说我们可以使用pair ,因为pair 内部安排了默认的排序方式:以first 为关键字 升序排列。
  • 设置哨兵是为了让查找不为空不返回空。

拓展知识点:

增广路径: 预先选一些匹配的边,从任一个不在匹配的点,先沿着非匹配边,再沿着匹配边走,。。。,交替,最后找到一个不在匹配里的点。(就找到了一个增广路径)。 如果一个匹配没有增广路径,则达到了最大匹配。

代码:

#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;

typedef pair<int ,int > pll;
const int N = 2510;

int n ,m;
pll cows[N];

int main(){
   
   
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)scanf("%d%d",&cows[i].first,&cows[i].second);
    sort(cows,cows+n);
    map<int,int >spfs;
    for(int i=0;i<m;++i){
   
   
        int x,cover;
        scanf("%d%d",&x,&cover);
        spfs[x] += cover;
    }
    int ans = 0;
    spfs[0] = spfs[1001] = n; // 哨兵,避免使用 查找函数时出错
    for(int i = n-1;i >= 0;--i){
   
   
        auto cow = cows[i];
        // 大于的最小的值
        auto it = spfs.upper_bound(cow.second); // 以区间的右边找 ,难点一
        it--; // 找到小于等于的最大值
        if(it->first >= cow.first && it->first <= cow.second){
   
   
            ans ++;
            if(-- it->second == 0)
                spfs.erase(it); // 难点二
        }
    }
    printf("%d\n",ans);
    return 0;    
}

畜栏预定

题目链接

解题思路:

  • 将所有牛按开始吃草的时间排序;
  • 用小根堆维护当前所有畜栏的最后一头牛的吃草结束时间;
  • 如果当前的牛可以安排在堆顶的畜栏中,则将其安排进去,否则就新建一个畜栏;

难点

  • 对于每头牛我们既要记录区间,还要记录编号。
  • 小根堆(即围栏)的更新操作。
  • 记录每头牛进入的围栏的编号。

技巧

  • 对于第一个难点我们可以用 pair<pair<int,int>,int>的方式来存储。
  • 对于第二个难点,我们小根堆里的元素类型也是 pair 这样我们记录两个元素一个了一头牛吃完草结束的时间,另一个是围栏的编号。所以在更新操作的时候我们把顶部的围栏拿出来修改得时候先把其删除,在更新结束时间的时候,把原来围栏的编号记录下。
  • 因为我们每头牛都有一个编号,而围栏也有,所以我们用一个数组来存储这两个对应的关系。其中牛的编号就是 0~n-1 ,围栏编号就是创建时小根堆中围栏元素个数。

代码:

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值