2034: [2009国家集训队]最大收益
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 498 Solved: 209
[ Submit][ Status][ Discuss]
Description
给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si, Ti]间的某个时刻,且完成后会有Vi的收益。求最大收益。 N≤5000,1 ≤ Si ≤ Ti ≤ 108,1 ≤ Vi ≤ 108。 澄清:一个时刻只能做一件任务,做一个任务也只需要一个时刻。
Input
第一行一个整数N,表示可供选择的任务个数. 接下来的第二到第N+1行,每行三个数,其中第i+1行依次为Si,Ti,Vi
Output
输出最大收益
Sample Input
4
1 1 2
2 2 2
1 2 3
1 3 1
1 1 2
2 2 2
1 2 3
1 3 1
Sample Output
6
HINT
共有四个任务,其中第一个任务只能在时刻1完成,第二个任务只能在时刻2做,第三个任务只能在时刻1或时刻2做,第四个任务可以在[1,3]内任一时刻完成,四个任务的价值分别为2、2、3和1。一种完成方案是:时刻1完成第一个任务,时刻2完成第三个任务,时刻3完成第四个任务,这样得到的总收益为2+3+1=6,为最大值。
分析:直接看论文
#include<bits/stdc++.h>
using namespace std;
#define N 5005
#define LL long long
struct node
{
int x, y, z, s;
}a[N];
int n, match[N], pos[N];
bool cmp1(const node &u, const node &v){return u.x < v.x;}
bool cmp2(const node &u, const node &v){return u.z > v.z;}
bool check(int k, int x)
{
if(pos[x]>a[k].y) return false;
if(!match[x])
{
match[x] = k;
return true;
}
else if(a[match[x]].y < a[k].y) return check(k, x+1);
else if(check(match[x], x+1))
{
match[x]=k;
return true;
}
else
return false;
}
int main()
{
scanf("%d", &n);int i;
for(i=1; i<=n; i++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
sort(a+1, a+n+1, cmp1);
for(i=1; i<=n; i++) pos[i]=max(pos[i-1]+1, a[i].x);
for(i=2, a[1].s=1; i<=n; i++)
{
a[i].s=a[i-1].s;
while(pos[a[i].s]<a[i].x&&a[i].s<n) a[i].s++;
}
sort(a+1, a+n+1, cmp2);
LL ans=0;
for(i=1; i<=n; i++) if(check(i, a[i].s)) ans+=a[i].z;
printf("%lld\n", ans);
return 0;
}