带权重的区间调度问题
Problem description
给定若干个工作的开始时间、结束时间和权重(可以理解成重要程度),求出能完成的最大的工作权重(尽可能地完成更重要的工作),当然必须满足各个工作相容。如以下三个工作:
开始时间 | 结束时间 | 权重 | |
---|---|---|---|
工作1 | 0 | 3 | 4 |
工作2 | 5 | 6 | 5 |
工作3 | 2 | 8 | 10 |
由不带权重的区间调度方法,依次结束时间最早且相容的工作,这里就选出{1, 2},能实现的最大权重是4+5=9。而显而易见,选择{3}权重可达到10,因此最早结束时间的贪心策略在带权重的区间调度问题里已不适用。
Analysis
各工作开始与结束时间
给出上图所示8个工作的开始结束时间,按结束时间升序排序(区间调度问题一般都会先按结束时间升序排序)。 数据说明如下:
- 工作数目n
- 声明结构体数组存储工作的开始、结束时间和权值
struct JOB{
int s, e, v;
JOB(int s=0, int e=0, int v=0):s(s), e(e), v(v){}
}job[maxn];
- dp[n]dp[i]表示对前1个工作考虑结束后所能达到的最大权值
- frt[n]frt[i]表示序列中前一与之相容的最大工作编号。如frt[8]=5,frt[6]=2
按结束时间排序
考虑状态转移方程。对于每个工作i,比较dp[i-1]和v[i]+dp[frt[i]],取较大者为dp[i]
状态转移方程
Code
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 205;
struct JOB{
int s, e, v, index;
JOB(int s=0, int e=0, int v=0, int index=0):s(s), e(e), v(v), index(index){}
}job[maxn];
int frt[maxn], dp[maxn];
bool cmpe(JOB a, JOB b){ //定义按结束时间升序排序的排序规则
return a.e<b.e;
}
/*bool cmps(JOB a, JOB b){ //定义按开始时间升序排序的排序规则
return a.s<b.s;
}*/
int main()
{
int n; cin >> n;
//JOB a=(1,2,3);
memset(frt, 0, sizeof(frt));
memset(dp, 0, sizeof(dp));
for(int i=1;i<=n;i++) cin >> job[i].s >> job[i].e >> job[i].v;
//按结束时间升序排序,并为元素编号
sort(job, job+n, cmpe);
for(int i=1; i<=n; i++) job[i].index=i;
//求frt[]数组
//sort(job, job+n, cmps); //按开始时间升序排列
for(int i=n;i>0;i--){
for(int j=n-1;j>0;j--){
if(job[j].e<=job[i].s) {frt[i]=job[j].index; break;}
}
}
//sort(job, job+n, cmpe);
for(int i=1;i<=n;i++){
dp[i] = max(dp[i-1], dp[frt[i]]+job[i].v);
}
cout << dp[n];
return 0;
}
Ref
1、带权重的区间调度问题——动态规划.
2、Weighted Interval Scheduling VS Interval Scheduling.
3、Weighted Interval Scheduling.