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 }