jzoj1669. 最大收益

题目描述

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值