区间调度问题_多线程

区间调度问题_单线程是一个人,这里是k个人。

题目:

https://nanti.jisuanke.com/t/28880

有n项工作,k个人,每项工作分别在si开始,ti结束。对每项工作,人都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,注意(x1,y1) (x2,y2) y1==x2 不算重叠。求最多参加几项工作。

样例输入

5 2
1 4
5 9
2 7
3 8
6 10

样例输出

3

思路:

贪心+模拟

首先按照结束时间从小到大排序,如果结束时间相同,那么按照开始时间从小到大排序。

用multiset容器进行模拟(开始和结束时间能重叠时用multiset,不能重叠时用set),规定multiset容器中存的是当前选泽的活动的结束时间,然后开始遍历其他的活动,如果当前所遍历的活动的开始时间大于所选择的活动的结束时间(只大于其中一个就可以,假设大于编号为i的活动的结束时间),我们就把当前所遍历的活动的结束时间放到muliset中去,覆盖掉i活动的结束时间。否则,就不往muliset中加入(即不选择这个活动)。

注意:初始的时候我们往muliset中放入k个0。

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
struct node
{
    int begin,end;
}a[MAXN];
int n,k;
multiset < int >q;
multiset < int >::iterator it;
bool cmp(node a,node b)//定义比较器
{
    if(a.end==b.end)
        return a.begin<b.begin;
    return a.end<b.end;
}
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>a[i].begin>>a[i].end;
    sort(a,a+n,cmp);
    for(int i=0;i<k;i++)
        q.insert(0);//先要往muliset中放入k个0
    int sum=0;
    for(int i=0;i<n;i++)
    {
        it=q.upper_bound(a[i].begin);//这句话的意思是找到容器中大于a[i].begin的第一个元素的位置
        if(it==q.begin())//如果这个条件满足,说明muliset中所有元素都大于a[i].begin,说明这个活动不选择
            continue ;
        it--;
        q.erase(it);//删除活动结束时间小于等于a[i].begin的结束时间最小的活动
        q.insert(a[i].end);//添加该活动的结束时间  这个地方删一个,加一个,可以保证muliset中始终有k个元素
        sum++;//计数
    }
    cout<<sum<<endl;;
}

猜你喜欢

转载自blog.csdn.net/aaakkk_1996/article/details/81627346