BZOJ[2034] [2009国家集训队]最大收益

 这是一个二分图匹配+贪心+离散

 首先,如果不考虑时间1e8的范围的话,直接将任务按照从大到小的顺序排序,然后直接最大匹配然后求和就行了

    但是,这道题的时间轴很长,会炸内存

    那么我们就将任务按照左端点排序,然后从小到大进行离散,然后用一个pos数组来记录离散后的i对应原来的左端点的真实值是多少

 然后再将任务照权值排序,从大到小进行匹配

    那么在匹配的时候,如果新编号的点没有被匹配,就直接匹配即可

    如果被匹配了,那么一定是这两个冲突的任务有一个的时间向后移动,因为在之前的任务都是尽可能的靠左端点匹配匹配的

 所以考虑到底是哪一个任务向后推

 那么这个时候既考虑哪一个的任务的r大就把哪个人物向后推,因为它包含的区间更多,如果他也匹配不了,那么小的更匹配不了

   

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 # define maxn 5010
 8 using namespace std;
 9 struct TEM{
10     int l,r,w;
11 }g[maxn];
12 bool cmp1(const TEM a,const TEM b){return a.l<b.l;}
13 bool cmp2(const TEM a,const TEM b){return a.w>b.w;}
14 int n;
15 int pos[maxn],ma[maxn];
16 bool find(int x,int d){
17     if(pos[d] > g[x].r) return 0;
18     if(!ma[d]){ma[d]=x; return 1;}
19     else{
20         if(g[ma[d]].r<g[x].r) return find(x,d+1);
21         else if(find(ma[d],d+1)){ma[d]=x; return 1;}
22         return 0;
23     }
24 }
25 int main(){
26     // freopen("a.in","r",stdin);
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++){
29         scanf("%d%d%d",&g[i].l,&g[i].r,&g[i].w);
30     }
31     sort(g+1,g+n+1,cmp1);
32     for(int i=1;i<=n;i++) pos[i]=max(pos[i-1]+1,g[i].l);
33     for(int i=1,j=1;i<=n;i++){
34         while(pos[j]<g[i].l) j++;
35         g[i].l=j;
36     }
37     long long ans=0;
38     sort(g+1,g+n+1,cmp2);
39     for(int i=1;i<=n;i++) if(find(i,g[i].l)) ans+=g[i].w;
40     cout<<ans<<endl;
41     return 0;
42 }

 

posted @ 2017-10-02 17:59  Nawox  阅读(201)  评论(0编辑  收藏  举报