Problem_1027

Problem_1027

带权活动选择
Time Limit: 3000 MSMemory 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值