带权重的区间调度问题——动态规划

问题阐述

  给定若干个工作的开始时间、结束时间和权重(可以理解成重要程度),求出能完成的最大的工作权重(尽可能地完成更重要的工作),当然必须满足各个工作相容。如以下三个工作:
              开始时间    结束时间    权重
工作1           0               3              4
工作2           5               6              5
工作3           2               8             10
  由不带权重的区间调度方法,依次结束时间最早且相容的工作,这里就选出{1, 2},能实现的最大权重是4+5=9。而显而易见,选择{3}权重可达到10,因此最早结束时间的贪心策略在带权重的区间调度问题里已不适用

分析

各工作开始与结束时间

  给出上图所示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]

状态转移方程

代码实现

#include 
#include 
#include 

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> 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;
}

老师的ppt里有一句话,“按开始时间排序后,计算frt数组的复杂度为O(n)”,但我没想出来怎么个O(n)法,上面代码还是用的简单的遍历,希望看到这里的朋友能不吝赐教>_<

Tips

  • 自定义sort函数的排序规则
  • 在O(nlogn)时间内计算frt数组的技巧(我不知道)

你可能感兴趣的:(带权重的区间调度问题——动态规划)