HDU_4864_Tasks_贪心

手机没电了没带充电器怎么办?


题意:

有m个任务,每个任务有两个参数x,y,有n个机器,每个机器有两个参数x,y,当机器的x和y分别大于某任务的x,y时,机器可以完成该项任务。每个机器只能做一个任务,完成一项任务可以获得价值500*x+2*y。求一种分配方案,使得完成的任务数最多,如果有多种方案,求获得价值最大的那一个。



Input
The input contains several test cases.
The first line contains two integers N and M. N is the number of the machines.M is the number of tasks(1 < =N <= 100000,1<=M<=100000).
The following N lines each contains two integers xi(0<xi<1440),yi(0=<yi<=100).xi is the maximum time the machine can work.yi is the level of the machine.
The following M lines each contains two integers xi(0<xi<1440),yi(0=<yi<=100).xi is the time we need to complete the task.yi is the level of the task.
 

Output
For each test case, output two integers, the maximum number of the tasks which the company can complete today and the money they will get.
 

Sample Input
  
  
1 2 100 3 100 2 100 1
 

Sample Output
  
  
1 50004

比赛的时候这题是我做的。。。。然后做法完全不对。。。。这个题有贪心策略,我没发现。。。。。。

观察x和y的数据范围可以发现,两个任务y的最大差是100,而价值的表达式为500*x+2*y,y造成的差别最大是200,x造成的最小差别(除了相等的情况)是500,因此如果x不一样,肯定是x大的任务价值大,即任务价值可以按先x后y的方法排序。这个性质在后面会用到一丢丢。


第一步贪心,我们按价值排序,从价值大的任务开始分配机器。对这个贪心,我们有两个猜想:

1. 这样分配价值肯定会最大

2. 这样分配完成任务数不会因为这个贪心受影响(这么说是因为之后的贪心也会影响任务数)

先证第二点,如果不从价值大的开始排序,意味着存在价值较大且可以完成的任务t1,不选择它我们可以完成价值较小的任务t2, t3, ...,这显然不可能,t1只跟完成它的机器有关,不做t1造成的影响只是空出一台机器,一台机器只能做一个任务,因此无法增加任务。

这样就好证第一点了,既然完成任务数不变(之后选择机器的贪心策略相同的情况下),选择价值更大的机器就能满足题目第二条要求。


第二部贪心,我们循环每一个任务,对于所有“价值”大于等于当前任务的机器,我们选择y大于等于当前机器y中最小的那个机器来做这个任务(lower_bound操作)。

这步贪心要用到之前的性质,价值大于等于当前任务的机器,它的x值必然大于等于当前任务,然后我们再找出其中y满足条件的所有机器,选取其中最小的。

对于y为什么选最小的:

因为我们按照价值从大到小的顺序处理任务,即按x从大到小的顺序,因此后面要处理的任务x必然比当前任务x要小,所以当前选出的可以完成任务机器的集合里的所有机器在x上都可以胜任,但是y不一定,所以要选择y尽可能小的,把y大的机器留给后面的任务。


实现上来说,建结构体存任务和机器,重载小于号按价值或者x大小。sort排序任务和机器,任务从大到小循环,用一个map<int,int>维护比当前任务价值大的机器,对每个任务lower_bound找y>=任务y的最小机器,处理结果从map中删除。

语法上来说我才知道map<int,int>原来不存在的key对应的value好像默认会是0。。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<map>
using namespace std;
#define mxn 100010
#define mxm 100010
struct item{
    int x,y;
    bool operator < (const item& in)const{
        return 500*x+2*y>500*in.x+2*in.y;
    }
    long long value(){
        return 500*x+2*y;
    }
};
item task[mxm],mac[mxn];
int n,m;
map<int,int>mp;
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=0;i<n;++i)    scanf("%d%d",&mac[i].x,&mac[i].y);
        for(int i=0;i<m;++i)    scanf("%d%d",&task[i].x,&task[i].y);
        sort(mac,mac+n);
        sort(task,task+m);
        mp.clear();
        int now=0;
        int cnt=0;
        long long ans=0;
        map<int,int>::iterator it;
        for(int i=0;i<m;++i){
            while(now<n&&mac[now].x>=task[i].x)
                ++mp[mac[now++].y];
            it=mp.lower_bound(task[i].y);
            if(it!=mp.end()){
                ans+=task[i].value();
                ++cnt;
                int tem=it->first;
                --mp[tem];
                if(!mp[tem])    mp.erase(tem);
            }
        }
        printf("%d %I64d\n",cnt,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值