链接:http://acm.hdu.edu.cn/showproblem.php?pid=4864
题意:某公司有m个任务需要完成。第i个任务需要xi的时间来完成。同时,该任务还有一个难度系数level yi。如果一个机器的难度系数小于level yi,
则该机器不能处理该任务。如果该公司完成了一个任务,则能获得500*xi+2*yi的收益。
该公司有n台机器,每个机器有一个最大工作时间xi,该时间只有大于任务需要的时间且该机器的难度系数大于任务的难度系数时,该机器才能处理
该任务。 每个机器每天只能处理一个任务。
求该公司能获得的最大收益。
思路:贪心。我觉得这道题贪心的时候,很容易想当然,认为机器的时间和等级尽量大去满足一个任务。
也就是说,需要对机器的时间和等级按照降序排列,对任务也做同样处理。然后,再去一个个对应。而这样
是错误的。以下几组数据可以验证这个方法的错误:
machine task
100 6 100 3
100 3 50 5
——————————
200 2 150 2
150 10 100 10
——————————
70 4 40 6
30 2 40 3
正确的方法是:对于价值c=500*xi+2*yi,yi最大影响100*2<500,所以就是求xi总和最大。可以先对机器和任务的时间从大到小排序。
从最大时间的任务开始,找出满足任务时间要求的所有机器,从中找出等级最低且满足任务等级要求的机器匹配。依次对任务寻找满足要求的机器。
(以上内容来自杭电官方解题报告)加粗的那句话是关键。
贪心准则找到了,下面就是怎么找这个等级最低的机器的问题了。一般找法就是暴力啦,果断TLE。然后想到要用二分查找。但是在匹配过程中,机器是
要被删除的,这样就不能实现一般的二分了(用数组存储的)。
然后,就用STL了。。这个具体看程序吧。
#include<cstdio>
#include<string.h>
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#define MAX 100005
using namespace std;
int n,m;
map<int,int> mapp;
struct machine
{
int minute,level;
}mach[MAX];
struct Task
{
int minute,level;
}task[MAX];
int cmp(Task a,Task b)
{
if(a.minute==b.minute)
return a.level>b.level;
return a.minute>b.minute;
}
int cnp(machine a,machine b)
{
if(a.minute==b.minute)
return a.level>b.level;
return a.minute>b.minute;
}
int main()
{
__int64 money;
int cnt,i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
money=0;
cnt=0;
for(i=0;i<n;i++)
scanf("%d%d",&mach[i].minute,&mach[i].level);
for(i=0;i<m;i++)
scanf("%d%d",&task[i].minute,&task[i].level);
sort(task,task+m,cmp);
sort(mach,mach+n,cnp);
mapp.clear();
j=0,cnt=0,money=0;
for(i=0;i<m;i++)
{
while(j<n&&mach[j].minute>=task[i].minute)
{
mapp[mach[j].level]++; //把满足时间要求的所有机器选出来
j++;
}
map<int,int>::iterator it=mapp.lower_bound(task[i].level); //二分查找
if(it!=mapp.end())
{
cnt++;
money+=(task[i].minute*500)+task[i].level*2;
int t=it->first;
mapp[t]--; //删除对应的机器,用STL的优势就体现在这里啦
if(mapp[t]==0) //不影响整体
mapp.erase(t);
}
}
printf("%d %I64d\n",cnt,money);
}
}