题目描述
Description
给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si, Ti]间的某个时刻,且完成后会有Vi的收益。求最大收益。
澄清:一个时刻只能做一件任务,做一个任务也只需要一个时刻。
Input
第一行一个整数N,表示可供选择的任务个数.
接下来的第二到第N+1行,每行三个数,其中第i+1行依次为Si,Ti,Vi
Output
输出最大收益
Sample Input
输入1:
2
1 1 1
1 1 2
输入2:
3
1 1 5
2 2 3
1 2 4
输入3:
6
1 2 10
2 3 10
3 4 10
4 5 10
1 1 5
5 5 6
Sample Output
输出1:
2
样例1解释:
选择第二个任务可以得到价值2。
输出2:
9
样例2解释:
在第一个时刻完成任务一,在第二个时刻完成任务三,这样得到最大总价值9。
输出3:
46
样例3解释:
时刻1完成第一个任务,时刻2完成第二个任务,时刻3完成第三个任务,时刻4完成第四个任务,时刻5完成第六个任务,所得的总收益是10+10+10+10+6=46,为最大收益。
Data Constraint
在占12%分数的数据中有N≤20。
在占30%分数的数据中有N≤500。
在所有数据中,N≤5000,1≤Si≤Ti≤108,1≤Vi≤108。
?%
一个显然的错误解法:
贪心,按收益从大到小加区间,能加则加(这个是对的)
然后排序+维护左端点
但这样会挂
51%
在上面的基础上加上堆维护右端点,每次把合法的区间右端点丢进去
每次取最小的右端点判断是否合法
时间复杂度:O(n2log n)
100%
因为带了一个log所以会T
考虑把log去掉
贪心加区间,每次加到x(x=Si)上
如果和其它区间冲突,那么带一个T更大的去x+1找
(因为无论如何都要带一个走,那么肯定带T更大的那个)
这样做本质是匈牙利,因为有了上面的贪心就可以优化到O(n2)
code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define len 10000007
using namespace std;
int hash[len+1][2];
int n,i,j,k,l;
long long ans;
struct Type{
int x,y,v;
} a[5001];
int Hash(int t,int s,bool type)
{
int i=t%len;
while (hash[i][0] && hash[i][0]!=t)
i=(i+1)%len;
if (!type)
return hash[i][1];
hash[i][0]=t;
hash[i][1]=s;
}
bool Cmp(Type a,Type b)
{
return a.v>b.v;
}
bool find(int t,int x)
{
int i,T;
if (x>a[t].y)
return 0;
T=Hash(x,t,0);
if (!T)
{
Hash(x,t,1);
return 1;
}
if (a[t].y<a[T].y)
{
if (find(T,x+1))
{
Hash(x,t,1);
return 1;
}
}
else
if (find(t,x+1))
return 1;
return 0;
}
int main()
{
// freopen("income15.in","r",stdin);
// freopen("S8_1_1.in","r",stdin);
scanf("%d",&n);
fo(i,1,n)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
sort(a+1,a+n+1,Cmp);
fo(i,1,n)
if (find(i,a[i].x))
ans+=a[i].v;
printf("%lld\n",ans);
}