算法竞赛进阶指南0x10练习13:Task

原题链接

今天某公司有 M 个任务需要完成。

每个任务都有相应的难度级别和完成任务所需时间。

第 i 个任务的难度级别为 yi,完成任务所需时间为 xi 分钟。

如果公司完成此任务,他们将获得(500×xi+2×yi)美元收入。

该公司有 N 台机器,每台机器都有最长工作时间和级别。

如果任务所需时间超过机器的最长工作时间,则机器无法完成此任务。

如果任务难度级别超过机器的级别,则机器无法完成次任务。

每台机器一天内只能完成一项任务。

每个任务只能由一台机器完成。

请为他们设计一个任务分配方案,使得该公司能够最大化他们今天可以完成的任务数量。

如果有多种解决方案,他们希望选取赚取利润最高的那种。

输入格式

输入包含几个测试用例。

对于每个测试用例,第一行包含两个整数 N 和 M,分别代表机器数量和任务数量。

接下来 N 行,每行包含两个整数 xi, yi,分别代表机器最长工作时间和机器级别。

再接下来 M 行,每行包含两个整数 xi, yi,分别代表完成任务所需时间和任务难度级别。

输出格式

对于每个测试用例,输出两个整数,代表公司今天可以完成的最大任务数以及他们将获得的收入。

数据范围

1≤N,M≤100000,
0<xi<1440,
0≤yi≤100

输入样例:

1 2
100 3
100 2
100 1

输出样例:

1 50004

思路:(贪心)

防晒那道题的进阶版;

对于每个任务而言,x变化1,利润就变化500,y变化1,利润变化2,

所以x对利润影响更大,优先考虑x;

因为利润和任务密切相关,所以我们方便计算利润,给任务分配机器解决问题;

我们站在任务的视角去给任务分配机器,将任务从大到小排序,

对于每个任务,分配机器中等级>=它的等级中最小的,这样可以减少对其他机器和任务的影响;

假设任务1等级为2,任务2等级为1,机器1等级为2,机器2等级为1,要使利润最大,

任务1应该分配给机器1,这样任务2可以分配给机器2,如果任务2分配给机器1,任务1无法分配给机器2;

看不懂可以看y总讲解

解法:

从大到小,枚举每个任务,将执行时间>=它的时间的机器等级加入到一个集合,

从集合里面选等级>=它最小的一个机器;

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
const int N=1e5+10;
pair<int,int> mch[N],task[N];//mch表示机器,task表示任务;
int main()
{
    int n,m;
    while(cin>>n>>m){
        for(int i=0;i<n;++i) cin>>mch[i].first>>mch[i].second;
        for(int i=0;i<m;++i) cin>>task[i].first>>task[i].second;
        sort(mch,mch+n);//降序排序
        sort(task,task+m);//降序排序
        multiset<int>st;//multiset表示值可重复的集合;
        long long res=0,cnt=0;
        for(int i=m-1,j=n-1;i>=0;i--){//升序从后往前枚举任务,i表示任务编号,j表示机器;
            int x=task[i].first,y=task[i].second;
            while(j>=0&&mch[j].first>=x) st.insert(mch[j--].second);//将工作时间>=任务时间的机器的等级加入集合;
            auto it=st.lower_bound(y);//寻找>=任务等级中最小的;
            if(it!=st.end()){
                cnt++;//计算任务数量
                res+=x*500+y*2;//计算利润;
                st.erase(it);//用过的机器就删除;
            }
        }
        cout<<cnt<<' '<<res<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值