贪心算法[区间分组详解包教包会]

区间分组问题是将n个区间分成若干个组。
方法一般是
1.将区间的左端点从小到大排序
2.从前往后处理每个区间
[一般定义一个堆:
priority_queue<int,vector,greater> heap;]

 if(可以放进当前组)直接放进当前组,并更新组的数据
 else 建立一个新的组

给定N个闭区间[ai,bi ],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。

输出最小组数。 输入格式

第一行包含整数N,表示区间数。

接下来N行,每行包含两个整数ai,bi

,表示一个区间的两个端点。 输出格式

输出一个整数,表示最小组数。 数据范围

1≤N≤105 , −109≤ai≤bi≤109

输入样例:

3
-1 1
2 4
3 5

输出样例:

2

此题可以看出要放进一个组的条件是
堆顶区间右端点<当前区间左端点
在这里插入图片描述heap为空(-1,1)放进当前组1
1<2 可以放进当前组 (2,4)放进当前组1,并弹出堆顶
4>3 不能放进当前组 (3,5)放进新的组2

代码:

#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1000010;
struct Range{
    int l,r;
    bool operator< (const Range& w)const{
        return l<w.l;//自定义比较函数使得从小到大排序
    }
}range[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        cin>>l>>r;
        range[i]={l,r};
    }
    
    sort(range,range+n);//从左到右排序
    //堆
    priority_queue<int,vector<int>,greater<int>> heap;
    
    for(int i=0;i<n;i++)
    {
        if(heap.empty()||heap.top()>=range[i].l)
        {
          //不满足条件新增组
            heap.push(range[i].r);
             // cout<<heap.top()<<endl;
        }
        else{
                      //  cout<<heap.top()<<endl;
            //满足条件弹出堆顶,放入当前组
            heap.pop();
            heap.push(range[i].r);
        }
    }
    cout<<heap.size();
    return 0;
}

才学一题是不是感觉还没掌握呢?
那再来一题吧

有N头牛在畜栏中吃草。

每个畜栏在同一时间段只能提供给一头牛吃草,所以可能会需要多个畜栏。

给定N头牛和每头牛开始吃草的时间A以及结束吃草的时间B,每头牛在[A,B]这一时间段内都会一直吃草。

当两头牛的吃草区间存在交集时(包括端点),这两头牛不能被安排在同一个畜栏吃草。

求需要的最小畜栏数目和每头牛对应的畜栏方案。 输入格式

第1行:输入一个整数N。

第2…N+1行:第i+1行输入第i头牛的开始吃草时间A以及结束吃草时间B,数之间用空格隔开。 输出格式

第1行:输入一个整数,代表所需最小畜栏数。

第2…N+1行:第i+1行输入第i头牛被安排到的畜栏编号,编号是从1开始的 连续 整数,只要方案合法即可。 数据范围

1≤N≤50000 , 1≤A,B≤1000000

输入样例:

5
1 10
2 4
3 6
5 8
4 7

输出样例:

4
1
2
3
2
4

这题和上题其实几乎是一个道理
还是堆顶区间右端点<当前区间左端点

在这里插入图片描述
heap为空(1,10)放进当前组1[橙色]
10>2 不能放进当前组 (2,4)放进新的组2[紫]
4>3 不能放进当前组 (3,6)放进新的组3[紫]
4<5 可以放进当前组 (5,8)放进当前组2[紫]并弹出堆顶
6>4 不能放当前组 (4,7)放进新的组4[粉]

故有四个组 排列为 1 2 3 2 4

废话少说上代码

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int N=500010;
struct Range
{
    int l,r,index;//当前是第几头牛
    bool operator< (const Range &W)const{
        return l<W.l;
    }
}range[N];

struct cmp
{
    template <typename T, typename U>
    bool operator()(T const &left, U const &right)
    {
    // 左端点进行排序
        if (left.first > right.first)
            return true;
        return false;
    }
};
int res[N];//存放围栏结果
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        cin>>l>>r;
        range[i]={l,r,i};
    }
    
    sort(range,range+n);
    priority_queue<pair<int,int>,vector<pair<int, int>>,cmp> heap;
    int min=1e7;
    int res_count=0;
    pair<int,int> p;
    for(int i=0;i<n;i++)
    {
        p.first=range[i].r;

        if(heap.empty()||heap.top().first>=range[i].l)//不满足条件建新围栏
        {
            //围栏总数++,记录当前围栏的是几号
            res[range[i].index]=p.second=++res_count;

            heap.push(p);
               //     cout<<heap.top().first<<"   "<<range[i].l<<"  ";
        }
        else//满足条件用旧围栏
        {
        //当前围栏号等于堆顶围栏号
            p.second=res[range[i].index]=heap.top().second;
            heap.pop();
            heap.push(p);
        }
                  // cout<<p.first<<"  "<<res[range[i].index]<<endl;
    }
    cout<<res_count<<endl;
    for(int i=0;i<n;i++)
    {
        cout<<res[i]<<endl;
    }
    return 0;
}

版权声明:本文为bwabdbkjdbkjwabd原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。