Problem_1027
带权活动选择 | ||
---|---|---|
Time Limit: 3000 MS | Memory Limit: 1000 KB |
Description
给定n个活动,活动ai表示为一个三元组(si,fi,vi),其中si表示活动开始时间,fi表示活动的结束时间,vi表示活动的权重,
si<fi。带权活动选择问题是选择一些活动,使得任意被选择的两个活动ai和aj执行时间互不相交,即区间[si,fi)与[sj,fj)
互不重叠,并且被选择的活动的权重和最大。请设计一种方法求解带权活动选择问题。
Input
第一行输入M(M<=10)表示有M组数据。每组数据输入整数N(N<=10000), 接下来输入N个活动。
Output
输出M行正整数,第i行表示第i组数据的能够选择活动最大权值和。
Sample Input
2
5
7 9 9
7 8 1
6 7 9
6 8 5
4 9 9
5
4 7 9
3 4 4
7 8 8
8 9 6
4 5 9
Sample Output
18
27
思考过程
依照以前做过的区间贪心,先对三元组按照结束事件排个序,然后利用区间DP
①dp[i]表示前i项活动的最大收益
②如果当前第i个活动不参加的话,那么最大收益是dp[i-1],
如果参加的话需要和前面的活动不冲突,此处可以定义一个数组cof[n]来记录当前活动的上一个不冲突的活动,dp[i]=dp[cof[i]]+val[i];
dp[i]=max(dp[i-1],dp[cof[i]]+val[i]),val[i]指第i个活动的收益
代码实现
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct Party{
int st;
int ed;
int vl;
int id;
}party[10001];
int frt[10001],dp[10001];
bool cmp(Party p1,Party p2){
return p1.ed<p2.ed;
}
int main()
{
int m;
int n;
cin>>m;
while(m--){
cin>>n;
memset(frt,0,sizeof(frt));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;++i){
cin>>party[i].st>>party[i].ed>>party[i].vl;
}
sort(party+1,party+n+1,cmp);
for(int i=1;i<=n;++i) party[i].id=i;
for(int i=n;i>=1;--i){
for(int j=n-1;j>=1;--j){
if(party[j].ed<=party[i].st){
frt[i]=party[j].id;break;
}
}
}
for(int i=1;i<=n;++i){
dp[i]=max(dp[i-1],dp[frt[i]]+party[i].vl);
}
cout<<dp[n]<<endl;
}
return 0;
}