• 二分图+贪心优化 [2009国家集训队]最大收益


    问题 B: [2009国家集训队]最大收益
    时间限制: 1 Sec 内存限制: 259 MB
    题目描述
    给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si, Ti]间的某个时刻,且完成后会有Vi的收益。求最大收益。 N≤5000,1 ≤ Si ≤ Ti ≤ 108,1 ≤ Vi ≤ 108。 澄清:一个时刻只能做一件任务,做一个任务也只需要一个时刻。

    输入
    第一行一个整数N,表示可供选择的任务个数. 接下来的第二到第N+1行,每行三个数,其中第i+1行依次为Si,Ti,Vi

    输出
    输出最大收益

    样例输入
    4
    1 1 2
    2 2 2
    1 2 3
    1 3 1
    样例输出
    6
    提示
    共有四个任务,其中第一个任务只能在时刻1完成,第二个任务只能在时刻2做,第三个任务只能在时刻1或时刻2做,第四个任务可以在[1,3]内任一时刻完成,四个任务的价值分别为2、2、3和1。一种完成方案是:时刻1完成第一个任务,时刻2完成第三个任务,时刻3完成第四个任务,这样得到的总收益为2+3+1=6,为最大值。

    如果把每一个任务与其可匹配的区间内所有点连边,时空间都会炸掉。但是每个任务只在一个点完成,这里就有了两个优化。
    1.因为一个点只能满足一个任务,点与点间不会互相影响,所以先满足权值大的任务一定最优。贪心get
    2.因此只会有至多N个时间点被利用,所以只要找出满足的N个点就好了。空间get
    那么来说说怎么找.因为一个区间里有很多点,如果第一个点符合,就没必要再向后找了。按左端点排序任务,如果左端点已被标记,那么就标记后面第一个没被标记的就好了。(小优化:记录下每个任务可以从第几个点开始找能否匹配)
    光这么打还是会TLE的。。亲身体验。。另一个优化:匹配二分图时,如果当前的时间点被匹配了,有两种选择,1.让当前任务和下一个点匹配;2.让当前时间点匹配的任务去和下一个时间点匹配。那么优化来了。设与当前时间点匹配的任务是A,而正在匹配的任务是B,如果A的右端点在B的右端点之前,那么把A向后边的时间点匹配,能成功那B也一定能成功,但A不成功B还可能成功。。。否则同理,所以只有B的右端点在A的右边,才去让B和后面的时间点匹配。否则直接让A去匹配就行了。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int n,v[5005],pro[5005];
    struct node{int l,r,x;ll h;}a[5005];
    inline bool find(int x,int s)
    {
           if(pro[s]>a[x].r)return 0;
           if(!v[s]){v[s]=x;return 1;}
           else
           {
    
               if(a[v[s]].r<a[x].r)return find(x,s+1);
               if(find(v[s],s+1)){v[s]=x;return 1;}
           }
           return 0;
    }
    inline bool cmpx(node x,node y){return x.l==y.l?x.r<y.r:x.l<y.l;}
    inline bool cmph(node x,node y){return x.h>y.h;}
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d%d%lld",&a[i].l,&a[i].r,&a[i].h);
        sort(a+1,a+n+1,cmpx);a[0].x=1;
        for(int i=1;i<=n;i++)
        {
            if(a[i].l<=pro[i-1])pro[i]=pro[i-1]+1;
            else pro[i]=a[i].l;
            a[i].x=a[i-1].x;
            while(pro[a[i].x]<a[i].l&&a[i].x<n)a[i].x++;
        }
        sort(a+1,a+n+1,cmph);
        ll ans=0;
        for(int i=1;i<=n;i++)if(find(i,a[i].x))ans+=a[i].h;
        cout<<ans;
    }
  • 相关阅读:
    c# 生成、读取xml
    http长连接与短连接
    p.net 子页面刷新父页面,页面自动刷新方法汇总
    遍历页面上所有控件
    从数据库导入到Excel表格(同时传四个表的数据到一个Excel中)
    .net海量数据分页通用存储过程
    SQL大数据量分页存储过程效率测试
    给一个接口传递参数,并接收返回的参数
    在asp.net中长内容自动分页的实现.NET教程
    GridView72般技巧
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632645.html
Copyright © 2020-2023  润新知